• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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/base/string_helper.h"
19 #include "ecmascript/builtins/builtins.h"
20 #include "ecmascript/builtins/builtins_ark_tools.h"
21 #ifdef ARK_SUPPORT_INTL
22 #include "ecmascript/builtins/builtins_collator.h"
23 #include "ecmascript/builtins/builtins_date_time_format.h"
24 #include "ecmascript/builtins/builtins_number_format.h"
25 #endif
26 #include "ecmascript/builtins/builtins_global.h"
27 #include "ecmascript/builtins/builtins_object.h"
28 #include "ecmascript/builtins/builtins_promise.h"
29 #include "ecmascript/builtins/builtins_promise_handler.h"
30 #include "ecmascript/builtins/builtins_proxy.h"
31 #include "ecmascript/builtins/builtins_regexp.h"
32 #include "ecmascript/compiler/builtins/builtins_call_signature.h"
33 #include "ecmascript/compiler/call_signature.h"
34 #include "ecmascript/compiler/common_stubs.h"
35 #include "ecmascript/compiler/interpreter_stub.h"
36 #include "ecmascript/compiler/rt_call_signature.h"
37 #include "ecmascript/jit/jit.h"
38 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
39 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
40 #endif
41 #if !WIN_OR_MAC_OR_IOS_PLATFORM
42 #include "ecmascript/dfx/hprof/heap_profiler.h"
43 #include "ecmascript/dfx/hprof/heap_profiler_interface.h"
44 #endif
45 #include "ecmascript/compiler/aot_file/an_file_data_manager.h"
46 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
47 #include "ecmascript/debugger/js_debugger_manager.h"
48 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
49 #include "ecmascript/dfx/tracing/tracing.h"
50 #include "ecmascript/dfx/vmstat/function_call_timer.h"
51 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
52 #include "ecmascript/dfx/vmstat/runtime_stat.h"
53 #include "ecmascript/ecma_context.h"
54 #include "ecmascript/ecma_string_table.h"
55 #include "ecmascript/global_env.h"
56 #include "ecmascript/global_env_constants-inl.h"
57 #include "ecmascript/global_env_constants.h"
58 #include "ecmascript/interpreter/interpreter-inl.h"
59 #include "ecmascript/jobs/micro_job_queue.h"
60 #include "ecmascript/js_arraybuffer.h"
61 #include "ecmascript/js_for_in_iterator.h"
62 #include "ecmascript/js_native_pointer.h"
63 #include "ecmascript/js_thread.h"
64 #include "ecmascript/jspandafile/constpool_value.h"
65 #include "ecmascript/jspandafile/js_pandafile.h"
66 #include "ecmascript/jspandafile/js_pandafile_manager.h"
67 #include "ecmascript/jspandafile/panda_file_translator.h"
68 #include "ecmascript/jspandafile/program_object.h"
69 #include "ecmascript/mem/concurrent_marker.h"
70 #include "ecmascript/mem/gc_stats.h"
71 #include "ecmascript/mem/heap.h"
72 #include "ecmascript/mem/mem.h"
73 #include "ecmascript/mem/space.h"
74 #include "ecmascript/mem/visitor.h"
75 #include "ecmascript/module/js_module_manager.h"
76 #include "ecmascript/module/module_data_extractor.h"
77 #include "ecmascript/module/module_path_helper.h"
78 #include "ecmascript/object_factory.h"
79 #include "ecmascript/patch/quick_fix_manager.h"
80 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
81 #include "ecmascript/regexp/regexp_parser_cache.h"
82 #include "ecmascript/runtime_call_id.h"
83 #include "ecmascript/snapshot/mem/snapshot.h"
84 #include "ecmascript/snapshot/mem/snapshot_env.h"
85 #include "ecmascript/stubs/runtime_stubs.h"
86 #include "ecmascript/tagged_array-inl.h"
87 #include "ecmascript/tagged_dictionary.h"
88 #include "ecmascript/tagged_queue.h"
89 #include "ecmascript/tagged_queue.h"
90 #include "ecmascript/taskpool/task.h"
91 #include "ecmascript/taskpool/taskpool.h"
92 #include "ecmascript/ts_types/ts_manager.h"
93 
94 #include "ecmascript/ohos/enable_aot_list_helper.h"
95 
96 namespace panda::ecmascript {
97 using RandomGenerator = base::RandomGenerator;
98 using PGOProfilerManager = pgo::PGOProfilerManager;
99 AOTFileManager *JsStackInfo::loader = nullptr;
100 /* static */
Create(const JSRuntimeOptions & options,EcmaParamConfiguration & config)101 EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options, EcmaParamConfiguration &config)
102 {
103     JSRuntimeOptions newOptions = options;
104     // only define SUPPORT_ENABLE_ASM_INTERP can enable asm-interpreter
105 #if !defined(SUPPORT_ENABLE_ASM_INTERP)
106     newOptions.SetEnableAsmInterpreter(false);
107 #endif
108     auto vm = new EcmaVM(newOptions, config);
109     if (UNLIKELY(vm == nullptr)) {
110         LOG_ECMA(ERROR) << "Failed to create jsvm";
111         return nullptr;
112     }
113     auto jsThread = JSThread::Create(vm);
114     vm->thread_ = jsThread;
115     vm->Initialize();
116     if (JsStackInfo::loader == nullptr) {
117         JsStackInfo::loader = vm->GetJSThread()->GetCurrentEcmaContext()->GetAOTFileManager();
118     }
119 #if defined(__aarch64__) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
120     if (SetThreadInfoCallback != nullptr) {
121         SetThreadInfoCallback(CrashCallback);
122     }
123 #endif
124     return vm;
125 }
126 
127 // static
Destroy(EcmaVM * vm)128 bool EcmaVM::Destroy(EcmaVM *vm)
129 {
130     if (vm != nullptr) {
131         delete vm;
132         vm = nullptr;
133         return true;
134     }
135     return false;
136 }
137 
PreFork()138 void EcmaVM::PreFork()
139 {
140     heap_->CompactHeapBeforeFork();
141     heap_->AdjustSpaceSizeForAppSpawn();
142     heap_->GetReadOnlySpace()->SetReadOnly();
143     heap_->DisableParallelGC();
144 }
145 
PostFork()146 void EcmaVM::PostFork()
147 {
148     RandomGenerator::InitRandom();
149     heap_->SetHeapMode(HeapMode::SHARE);
150     GetAssociatedJSThread()->SetThreadId();
151     heap_->EnableParallelGC();
152     std::string bundleName = PGOProfilerManager::GetInstance()->GetBundleName();
153     if (ohos::EnableAotListHelper::GetInstance()->IsDisableBlackList(bundleName)) {
154         options_.SetEnablePGOProfiler(false);
155         PGOProfilerManager::GetInstance()->SetDisableAot(true);
156     } else if (ohos::EnableAotListHelper::GetInstance()->IsEnableList(bundleName)) {
157         options_.SetEnablePGOProfiler(true);
158     }
159     ResetPGOProfiler();
160 #ifdef ENABLE_POSTFORK_FORCEEXPAND
161     heap_->NotifyPostFork();
162     heap_->NotifyFinishColdStartSoon();
163 #endif
164 }
165 
EcmaVM(JSRuntimeOptions options,EcmaParamConfiguration config)166 EcmaVM::EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config)
167     : stringTable_(new EcmaStringTable(this)),
168       nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
169       heapRegionAllocator_(std::make_unique<HeapRegionAllocator>()),
170       chunk_(nativeAreaAllocator_.get()),
171       ecmaParamConfiguration_(std::move(config))
172 {
173     options_ = std::move(options);
174     icEnabled_ = options_.EnableIC();
175     optionalLogEnabled_ = options_.EnableOptionalLog();
176     options_.ParseAsmInterOption();
177     SetEnableJit(options_.IsEnableJIT() && options_.GetEnableAsmInterpreter());
178 }
179 
InitializePGOProfiler()180 void EcmaVM::InitializePGOProfiler()
181 {
182     bool isEnablePGOProfiler = IsEnablePGOProfiler();
183     if (pgoProfiler_ == nullptr) {
184         pgoProfiler_ = PGOProfilerManager::GetInstance()->Build(this, isEnablePGOProfiler);
185     }
186     thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
187 }
188 
ResetPGOProfiler()189 void EcmaVM::ResetPGOProfiler()
190 {
191     if (pgoProfiler_ != nullptr) {
192         bool isEnablePGOProfiler = IsEnablePGOProfiler();
193         PGOProfilerManager::GetInstance()->Reset(pgoProfiler_, isEnablePGOProfiler);
194         thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
195         thread_->CheckOrSwitchPGOStubs();
196     }
197 }
198 
IsEnablePGOProfiler() const199 bool EcmaVM::IsEnablePGOProfiler() const
200 {
201     if (options_.IsWorker()) {
202         return PGOProfilerManager::GetInstance()->IsEnable();
203     }
204     return options_.GetEnableAsmInterpreter() && options_.IsEnablePGOProfiler();
205 }
206 
IsEnableElementsKind() const207 bool EcmaVM::IsEnableElementsKind() const
208 {
209     if (options_.IsWorker()) {
210         return false;
211     }
212     return options_.GetEnableAsmInterpreter() && options_.IsEnableElementsKind();
213 }
214 
Initialize()215 bool EcmaVM::Initialize()
216 {
217     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "EcmaVM::Initialize");
218     InitializePGOProfiler();
219     Taskpool::GetCurrentTaskpool()->Initialize();
220 #ifndef PANDA_TARGET_WINDOWS
221     RuntimeStubs::Initialize(thread_);
222 #endif
223     heap_ = new Heap(this);
224     heap_->Initialize();
225     gcStats_ = chunk_.New<GCStats>(heap_, options_.GetLongPauseTime());
226     factory_ = chunk_.New<ObjectFactory>(thread_, heap_);
227     if (UNLIKELY(factory_ == nullptr)) {
228         LOG_FULL(FATAL) << "alloc factory_ failed";
229         UNREACHABLE();
230     }
231     debuggerManager_ = chunk_.New<tooling::JsDebuggerManager>(this);
232     auto context = new EcmaContext(thread_);
233     thread_->PushContext(context);
234     [[maybe_unused]] EcmaHandleScope scope(thread_);
235     context->Initialize();
236     thread_->SetGlueGlobalEnv(reinterpret_cast<GlobalEnv *>(context->GetGlobalEnv().GetTaggedType()));
237     thread_->SetGlobalObject(GetGlobalEnv()->GetGlobalObject());
238     thread_->SetCurrentEcmaContext(context);
239     SingleCharTable::CreateSingleCharTable(thread_);
240     GenerateInternalNativeMethods();
241     quickFixManager_ = new QuickFixManager();
242     snapshotEnv_ = new SnapshotEnv(this);
243     if (options_.GetEnableAsmInterpreter()) {
244         thread_->GetCurrentEcmaContext()->LoadStubFile();
245     }
246 
247     callTimer_ = new FunctionCallTimer();
248     strategy_ = new ThroughputJSObjectResizingStrategy();
249 
250     if (IsEnableJit()) {
251         jit_ = new Jit(this);
252         jit_->Initialize();
253     }
254     initialized_ = true;
255     return true;
256 }
257 
~EcmaVM()258 EcmaVM::~EcmaVM()
259 {
260     initialized_ = false;
261 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
262     if (thread_->isProfiling_) {
263         if (profiler_->GetOutToFile()) {
264             DFXJSNApi::StopCpuProfilerForFile(this);
265         } else {
266             DFXJSNApi::StopCpuProfilerForInfo(this);
267         }
268     }
269 #endif
270 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
271     DeleteHeapProfile();
272 #endif
273     heap_->WaitAllTasksFinished();
274     Taskpool::GetCurrentTaskpool()->Destroy(thread_->GetThreadId());
275 
276     if (pgoProfiler_ != nullptr) {
277         PGOProfilerManager::GetInstance()->Destroy(pgoProfiler_);
278         pgoProfiler_ = nullptr;
279     }
280 
281 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
282     DumpCallTimeInfo();
283 #endif
284 
285 #if defined(ECMASCRIPT_SUPPORT_TRACING)
286     if (tracing_) {
287         DFXJSNApi::StopTracing(this);
288     }
289 #endif
290 
291     // clear c_address: c++ pointer delete
292     ClearBufferData();
293     if (!isBundlePack_) {
294         std::shared_ptr<JSPandaFile> jsPandaFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(assetPath_);
295         if (jsPandaFile != nullptr) {
296             jsPandaFile->DeleteParsedConstpoolVM(this);
297         }
298     }
299 
300     if (IsEnableJit()) {
301         if (jit_ != nullptr) {
302             delete jit_;
303             jit_ = nullptr;
304         }
305     }
306 
307     if (gcStats_ != nullptr) {
308         if (options_.EnableGCStatsPrint()) {
309             gcStats_->PrintStatisticResult();
310         }
311         chunk_.Delete(gcStats_);
312         gcStats_ = nullptr;
313     }
314 
315     if (JsStackInfo::loader == GetJSThread()->GetCurrentEcmaContext()->GetAOTFileManager()) {
316         JsStackInfo::loader = nullptr;
317     }
318 
319     if (heap_ != nullptr) {
320         heap_->Destroy();
321         delete heap_;
322         heap_ = nullptr;
323     }
324 
325     if (debuggerManager_ != nullptr) {
326         chunk_.Delete(debuggerManager_);
327         debuggerManager_ = nullptr;
328     }
329 
330     if (factory_ != nullptr) {
331         chunk_.Delete(factory_);
332         factory_ = nullptr;
333     }
334 
335     if (stringTable_ != nullptr) {
336         delete stringTable_;
337         stringTable_ = nullptr;
338     }
339 
340     if (quickFixManager_ != nullptr) {
341         delete quickFixManager_;
342         quickFixManager_ = nullptr;
343     }
344 
345     if (snapshotEnv_ != nullptr) {
346         delete snapshotEnv_;
347         snapshotEnv_ = nullptr;
348     }
349 
350     if (callTimer_ != nullptr) {
351         delete callTimer_;
352         callTimer_ = nullptr;
353     }
354 
355     if (strategy_ != nullptr) {
356         delete strategy_;
357         strategy_ = nullptr;
358     }
359 
360     if (thread_ != nullptr) {
361         delete thread_;
362         thread_ = nullptr;
363     }
364 }
365 
GetGlobalEnv() const366 JSHandle<GlobalEnv> EcmaVM::GetGlobalEnv() const
367 {
368     return thread_->GetCurrentEcmaContext()->GetGlobalEnv();
369 }
370 
FastCallAot(size_t actualNumArgs,JSTaggedType * args,const JSTaggedType * prevFp)371 JSTaggedValue EcmaVM::FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp)
372 {
373     INTERPRETER_TRACE(thread_, ExecuteAot);
374     auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_OptimizedFastCallEntry);
375     // do not modify this log to INFO, this will call many times
376     LOG_ECMA(DEBUG) << "start to execute aot entry: " << (void*)entry;
377     auto res = reinterpret_cast<FastCallAotEntryType>(entry)(thread_->GetGlueAddr(),
378                                                              actualNumArgs,
379                                                              args,
380                                                              reinterpret_cast<uintptr_t>(prevFp));
381     return res;
382 }
383 
CheckStartCpuProfiler()384 void EcmaVM::CheckStartCpuProfiler()
385 {
386 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
387     if (options_.EnableCpuProfilerColdStartMainThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
388         !options_.IsWorker() && profiler_ == nullptr) {
389         std::string fileName = options_.GetArkBundleName() + ".cpuprofile";
390         if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
391             LOG_ECMA(ERROR) << "createFile failed " << fileName;
392             return;
393         } else {
394             DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
395             return;
396         }
397     }
398 
399     if (options_.EnableCpuProfilerColdStartWorkerThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
400         options_.IsWorker() && profiler_ == nullptr) {
401         std::string fileName = options_.GetArkBundleName() + "_"
402                                + std::to_string(thread_->GetThreadId()) + ".cpuprofile";
403         if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
404             LOG_ECMA(ERROR) << "createFile failed " << fileName;
405             return;
406         } else {
407             DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
408             return;
409         }
410     }
411 #endif
412 }
413 
GetAndClearEcmaUncaughtException() const414 JSHandle<JSTaggedValue> EcmaVM::GetAndClearEcmaUncaughtException() const
415 {
416     JSHandle<JSTaggedValue> exceptionHandle = GetEcmaUncaughtException();
417     thread_->ClearException();  // clear for ohos app
418     return exceptionHandle;
419 }
420 
GetEcmaUncaughtException() const421 JSHandle<JSTaggedValue> EcmaVM::GetEcmaUncaughtException() const
422 {
423     if (!thread_->HasPendingException()) {
424         return JSHandle<JSTaggedValue>();
425     }
426     JSHandle<JSTaggedValue> exceptionHandle(thread_, thread_->GetException());
427     return exceptionHandle;
428 }
429 
PrintJSErrorInfo(const JSHandle<JSTaggedValue> & exceptionInfo) const430 void EcmaVM::PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo) const
431 {
432     EcmaContext::PrintJSErrorInfo(thread_, exceptionInfo);
433 }
434 
ProcessNativeDelete(const WeakRootVisitor & visitor)435 void EcmaVM::ProcessNativeDelete(const WeakRootVisitor &visitor)
436 {
437     if (!heap_->IsYoungGC()) {
438         auto iter = nativePointerList_.begin();
439         while (iter != nativePointerList_.end()) {
440             JSNativePointer *object = *iter;
441             auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
442             if (fwd == nullptr) {
443                 nativeAreaAllocator_->DecreaseNativeSizeStats(object->GetBindingSize(), object->GetNativeFlag());
444                 object->Destroy();
445                 iter = nativePointerList_.erase(iter);
446             } else {
447                 ++iter;
448             }
449         }
450     }
451 
452     thread_->GetCurrentEcmaContext()->ProcessNativeDelete(visitor);
453 }
454 
ProcessReferences(const WeakRootVisitor & visitor)455 void EcmaVM::ProcessReferences(const WeakRootVisitor &visitor)
456 {
457     if (thread_->GetCurrentEcmaContext()->GetRegExpParserCache() != nullptr) {
458         thread_->GetCurrentEcmaContext()->GetRegExpParserCache()->Clear();
459     }
460     if (!heap_->IsYoungGC()) {
461         heap_->ResetNativeBindingSize();
462         // array buffer
463         auto iter = nativePointerList_.begin();
464         while (iter != nativePointerList_.end()) {
465             JSNativePointer *object = *iter;
466             auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
467             if (fwd == nullptr) {
468                 nativeAreaAllocator_->DecreaseNativeSizeStats(object->GetBindingSize(), object->GetNativeFlag());
469                 object->Destroy();
470                 iter = nativePointerList_.erase(iter);
471                 continue;
472             }
473             heap_->IncreaseNativeBindingSize(JSNativePointer::Cast(fwd));
474             if (fwd != reinterpret_cast<TaggedObject *>(object)) {
475                 *iter = JSNativePointer::Cast(fwd);
476             }
477             ++iter;
478         }
479     }
480     thread_->GetCurrentEcmaContext()->ProcessReferences(visitor);
481     GetPGOProfiler()->ProcessReferences(visitor);
482 }
483 
PushToNativePointerList(JSNativePointer * pointer)484 void EcmaVM::PushToNativePointerList(JSNativePointer *pointer)
485 {
486     nativePointerList_.emplace_back(pointer);
487 }
488 
RemoveFromNativePointerList(JSNativePointer * pointer)489 void EcmaVM::RemoveFromNativePointerList(JSNativePointer *pointer)
490 {
491     auto iter = std::find(nativePointerList_.begin(), nativePointerList_.end(), pointer);
492     if (iter != nativePointerList_.end()) {
493         JSNativePointer *object = *iter;
494         nativeAreaAllocator_->DecreaseNativeSizeStats(object->GetBindingSize(), object->GetNativeFlag());
495         object->Destroy();
496         nativePointerList_.erase(iter);
497     }
498 }
499 
PushToDeregisterModuleList(CString module)500 void EcmaVM::PushToDeregisterModuleList(CString module)
501 {
502     deregisterModuleList_.emplace_back(module);
503 }
504 
RemoveFromDeregisterModuleList(CString module)505 void EcmaVM::RemoveFromDeregisterModuleList(CString module)
506 {
507     auto iter = std::find(deregisterModuleList_.begin(), deregisterModuleList_.end(), module);
508     if (iter != deregisterModuleList_.end()) {
509         deregisterModuleList_.erase(iter);
510     }
511 }
512 
ContainInDeregisterModuleList(CString module)513 bool EcmaVM::ContainInDeregisterModuleList(CString module)
514 {
515     return (std::find(deregisterModuleList_.begin(), deregisterModuleList_.end(), module)
516         != deregisterModuleList_.end());
517 }
518 
ClearBufferData()519 void EcmaVM::ClearBufferData()
520 {
521     for (auto iter : nativePointerList_) {
522         iter->Destroy();
523     }
524     nativePointerList_.clear();
525     thread_->GetCurrentEcmaContext()->ClearBufferData();
526     internalNativeMethods_.clear();
527     workerList_.clear();
528     deregisterModuleList_.clear();
529 }
530 
CollectGarbage(TriggerGCType gcType,GCReason reason) const531 void EcmaVM::CollectGarbage(TriggerGCType gcType, GCReason reason) const
532 {
533     heap_->CollectGarbage(gcType, reason);
534 }
535 
Iterate(const RootVisitor & v,const RootRangeVisitor & rv)536 void EcmaVM::Iterate(const RootVisitor &v, const RootRangeVisitor &rv)
537 {
538     rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&internalNativeMethods_.front())),
539         ObjectSlot(ToUintPtr(&internalNativeMethods_.back()) + JSTaggedValue::TaggedTypeSize()));
540     if (!WIN_OR_MAC_OR_IOS_PLATFORM) {
541         snapshotEnv_->Iterate(v);
542     }
543     pgoProfiler_->Iterate(v);
544 }
545 
546 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
DeleteHeapProfile()547 void EcmaVM::DeleteHeapProfile()
548 {
549     if (heapProfile_ == nullptr) {
550         return;
551     }
552     delete heapProfile_;
553     heapProfile_ = nullptr;
554 }
555 
GetHeapProfile()556 HeapProfilerInterface *EcmaVM::GetHeapProfile()
557 {
558     if (heapProfile_ != nullptr) {
559         return heapProfile_;
560     }
561     return nullptr;
562 }
563 
GetOrNewHeapProfile()564 HeapProfilerInterface *EcmaVM::GetOrNewHeapProfile()
565 {
566     if (heapProfile_ != nullptr) {
567         return heapProfile_;
568     }
569     heapProfile_ = new HeapProfiler(this);
570     ASSERT(heapProfile_ != nullptr);
571     return heapProfile_;
572 }
573 
StartHeapTracking()574 void EcmaVM::StartHeapTracking()
575 {
576     heap_->StartHeapTracking();
577 }
578 
StopHeapTracking()579 void EcmaVM::StopHeapTracking()
580 {
581     heap_->StopHeapTracking();
582 }
583 #endif
584 
585 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
586 void *EcmaVM::InternalMethodTable[] = {
587     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsBoundFunction),
588     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsProxy),
589     reinterpret_cast<void *>(builtins::BuiltinsObject::CreateDataPropertyOnObjectFunctions),
590 #ifdef ARK_SUPPORT_INTL
591     reinterpret_cast<void *>(builtins::BuiltinsCollator::AnonymousCollator),
592     reinterpret_cast<void *>(builtins::BuiltinsDateTimeFormat::AnonymousDateTimeFormat),
593     reinterpret_cast<void *>(builtins::BuiltinsNumberFormat::NumberFormatInternalFormatNumber),
594 #endif
595     reinterpret_cast<void *>(builtins::BuiltinsProxy::InvalidateProxyFunction),
596     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitFulfilled),
597     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitRejected),
598     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ResolveElementFunction),
599     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Resolve),
600     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Reject),
601     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Executor),
602     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AnyRejectElementFunction),
603     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledResolveElementFunction),
604     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledRejectElementFunction),
605     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ThenFinally),
606     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::CatchFinally),
607     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::valueThunkFunction),
608     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::throwerFunction),
609     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorFulfilledFunc),
610     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorRejectedFunc),
611     reinterpret_cast<void *>(JSAsyncFromSyncIterator::AsyncFromSyncIterUnwarpFunction),
612     reinterpret_cast<void *>(SourceTextModule::AsyncModuleFulfilledFunc),
613     reinterpret_cast<void *>(SourceTextModule::AsyncModuleRejectedFunc)
614 };
615 
GenerateInternalNativeMethods()616 void EcmaVM::GenerateInternalNativeMethods()
617 {
618     size_t length = static_cast<size_t>(MethodIndex::METHOD_END);
619     constexpr uint32_t numArgs = 2;  // function object and this
620     for (size_t i = 0; i < length; i++) {
621         auto method = factory_->NewMethod(nullptr, MemSpaceType::NON_MOVABLE);
622         method->SetNativePointer(InternalMethodTable[i]);
623         method->SetNativeBit(true);
624         method->SetNumArgsWithCallField(numArgs);
625         method->SetFunctionKind(FunctionKind::NORMAL_FUNCTION);
626         internalNativeMethods_.emplace_back(method.GetTaggedValue());
627     }
628 }
629 
GetMethodByIndex(MethodIndex idx)630 JSTaggedValue EcmaVM::GetMethodByIndex(MethodIndex idx)
631 {
632     auto index = static_cast<uint8_t>(idx);
633     ASSERT(index < internalNativeMethods_.size());
634     return internalNativeMethods_[index];
635 }
636 
TriggerConcurrentCallback(JSTaggedValue result,JSTaggedValue hint)637 void EcmaVM::TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint)
638 {
639     if (concurrentCallback_ == nullptr) {
640         LOG_ECMA(DEBUG) << "Only trigger concurrent callback in taskpool thread";
641         return;
642     }
643 
644     bool success = true;
645     if (result.IsJSPromise()) {
646         // Async concurrent will return Promise
647         auto promise = JSPromise::Cast(result.GetTaggedObject());
648         auto status = promise->GetPromiseState();
649         if (status == PromiseState::PENDING) {
650             result = JSHandle<JSTaggedValue>::Cast(factory_->GetJSError(
651                 ErrorType::ERROR, "Can't return Promise in pending state")).GetTaggedValue();
652         } else {
653             result = promise->GetPromiseResult();
654         }
655 
656         if (status != PromiseState::FULFILLED) {
657             success = false;
658         }
659     }
660 
661     JSHandle<JSTaggedValue> functionValue(thread_, hint);
662     if (!functionValue->IsJSFunction()) {
663         LOG_ECMA(ERROR) << "TriggerConcurrentCallback hint is not function";
664         return;
665     }
666     JSHandle<JSFunction> functionInfo(functionValue);
667     if (functionInfo->IsCallNapi()) {
668         LOG_ECMA(INFO) << "Function is not taskpool task";
669         return;
670     }
671     JSTaggedValue extraInfoValue = functionInfo->GetFunctionExtraInfo();
672     if (!extraInfoValue.IsJSNativePointer()) {
673         LOG_ECMA(INFO) << "FunctionExtraInfo is not JSNativePointer";
674         return;
675     }
676     JSHandle<JSNativePointer> extraInfo(thread_, extraInfoValue);
677     void *taskInfo = extraInfo->GetData();
678 
679     concurrentCallback_(JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, result)), success,
680                         taskInfo, concurrentData_);
681 }
682 
DumpCallTimeInfo()683 void EcmaVM::DumpCallTimeInfo()
684 {
685     if (callTimer_ != nullptr) {
686         callTimer_->PrintAllStats();
687     }
688 }
689 
WorkersetInfo(EcmaVM * workerVm)690 void EcmaVM::WorkersetInfo(EcmaVM *workerVm)
691 {
692     LockHolder lock(mutex_);
693     auto thread = workerVm->GetJSThread();
694     if (thread != nullptr) {
695         auto tid = thread->GetThreadId();
696         if (tid != 0) {
697             workerList_.emplace(tid, workerVm);
698         }
699     }
700 }
701 
GetWorkerVm(uint32_t tid)702 EcmaVM *EcmaVM::GetWorkerVm(uint32_t tid)
703 {
704     LockHolder lock(mutex_);
705     EcmaVM *workerVm = nullptr;
706     if (!workerList_.empty()) {
707         auto iter = workerList_.find(tid);
708         if (iter != workerList_.end()) {
709             workerVm = iter->second;
710         }
711     }
712     return workerVm;
713 }
714 
DeleteWorker(EcmaVM * workerVm)715 bool EcmaVM::DeleteWorker(EcmaVM *workerVm)
716 {
717     LockHolder lock(mutex_);
718     auto thread = workerVm->GetJSThread();
719     if (thread != nullptr) {
720         auto tid = thread->GetThreadId();
721         if (tid == 0) {
722             return false;
723         }
724         auto iter = workerList_.find(tid);
725         if (iter != workerList_.end()) {
726             workerList_.erase(iter);
727             return true;
728         }
729         return false;
730     }
731     return false;
732 }
733 
SuspendWorkerVm(uint32_t tid)734 bool EcmaVM::SuspendWorkerVm(uint32_t tid)
735 {
736     LockHolder lock(mutex_);
737     if (!workerList_.empty()) {
738         auto iter = workerList_.find(tid);
739         if (iter != workerList_.end()) {
740             return DFXJSNApi::SuspendVM(iter->second);
741         }
742     }
743     return false;
744 }
745 
ResumeWorkerVm(uint32_t tid)746 void EcmaVM::ResumeWorkerVm(uint32_t tid)
747 {
748     LockHolder lock(mutex_);
749     if (!workerList_.empty()) {
750         auto iter = workerList_.find(tid);
751         if (iter != workerList_.end()) {
752             DFXJSNApi::ResumeVM(iter->second);
753         }
754     }
755 }
756 
757 /*  This moduleName is a readOnly variable for napi, represent which abc is running in current vm.
758 *   Get Current recordName: bundleName/ets/xxx/xxx
759 *                           pkg_modules@xxx/xxx/xxx
760 *   Get Current fileName: /data/storage/el1/bundle/moduleName/ets/modules.abc
761 *   output: moduleName: moduleName
762 *   if needRecordName then fileName is: moduleName/ets/modules.abc
763 */
GetCurrentModuleInfo(bool needRecordName)764 std::pair<std::string, std::string> EcmaVM::GetCurrentModuleInfo(bool needRecordName)
765 {
766     std::pair<JSTaggedValue, JSTaggedValue> moduleInfo = EcmaInterpreter::GetCurrentEntryPoint(thread_);
767     CString recordName = ConvertToString(moduleInfo.first);
768     CString fileName = ConvertToString(moduleInfo.second);
769     LOG_FULL(INFO) << "Current recordName is " << recordName <<", current fileName is " << fileName;
770     if (needRecordName) {
771         if (fileName.length() > ModulePathHelper::BUNDLE_INSTALL_PATH_LEN &&
772             fileName.find(ModulePathHelper::BUNDLE_INSTALL_PATH) == 0) {
773             fileName = fileName.substr(ModulePathHelper::BUNDLE_INSTALL_PATH_LEN);
774         } else {
775             LOG_FULL(ERROR) << " GetCurrentModuleName Fail, fileName is " << fileName;
776         }
777         return std::make_pair(recordName.c_str(), fileName.c_str());
778     }
779     CString moduleName = ModulePathHelper::GetModuleName(recordName);
780     if (moduleName.empty()) {
781         LOG_FULL(ERROR) << " GetCurrentModuleName Fail, recordName is " << recordName;
782     }
783     return std::make_pair(moduleName.c_str(), fileName.c_str());
784 }
785 
SetHmsModuleList(const std::vector<panda::HmsMap> & list)786 void EcmaVM::SetHmsModuleList(const std::vector<panda::HmsMap> &list)
787 {
788     for (size_t i = 0; i < list.size(); i++) {
789         HmsMap hmsMap = list[i];
790         hmsModuleList_.emplace(hmsMap.originalPath.c_str(), hmsMap);
791     }
792 }
793 
GetHmsModule(const CString & module) const794 CString EcmaVM::GetHmsModule(const CString &module) const
795 {
796     auto it = hmsModuleList_.find(module);
797     if (it == hmsModuleList_.end()) {
798         LOG_ECMA(FATAL) << " Get Hms Module failed";
799     }
800     HmsMap hmsMap = it->second;
801     return hmsMap.targetPath.c_str();
802 }
803 
IsHmsModule(const CString & moduleStr) const804 bool EcmaVM::IsHmsModule(const CString &moduleStr) const
805 {
806     if (hmsModuleList_.empty()) {
807         return false;
808     }
809     auto it = hmsModuleList_.find(moduleStr);
810     if (it == hmsModuleList_.end()) {
811         return false;
812     }
813     return true;
814 }
815 }  // namespace panda::ecmascript
816