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