• 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/path_helper.h"
19 #include "ecmascript/base/string_helper.h"
20 #include "ecmascript/builtins/builtins.h"
21 #include "ecmascript/builtins/builtins_ark_tools.h"
22 #include "ecmascript/builtins/builtins_collator.h"
23 #include "ecmascript/builtins/builtins_date_time_format.h"
24 #include "ecmascript/builtins/builtins_global.h"
25 #include "ecmascript/builtins/builtins_number_format.h"
26 #include "ecmascript/builtins/builtins_object.h"
27 #include "ecmascript/builtins/builtins_promise.h"
28 #include "ecmascript/builtins/builtins_promise_handler.h"
29 #include "ecmascript/builtins/builtins_proxy.h"
30 #include "ecmascript/builtins/builtins_regexp.h"
31 #include "ecmascript/compiler/builtins/builtins_call_signature.h"
32 #include "ecmascript/compiler/call_signature.h"
33 #include "ecmascript/compiler/common_stubs.h"
34 #include "ecmascript/compiler/interpreter_stub.h"
35 #include "ecmascript/compiler/rt_call_signature.h"
36 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
37 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
38 #endif
39 #if !WIN_OR_MAC_OR_IOS_PLATFORM
40 #include "ecmascript/dfx/hprof/heap_profiler.h"
41 #include "ecmascript/dfx/hprof/heap_profiler_interface.h"
42 #endif
43 #include "ecmascript/debugger/js_debugger_manager.h"
44 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
45 #include "ecmascript/dfx/vmstat/runtime_stat.h"
46 #include "ecmascript/ecma_string_table.h"
47 #include "ecmascript/aot_file_manager.h"
48 #include "ecmascript/global_env.h"
49 #include "ecmascript/global_env_constants-inl.h"
50 #include "ecmascript/global_env_constants.h"
51 #include "ecmascript/interpreter/interpreter-inl.h"
52 #include "ecmascript/jobs/micro_job_queue.h"
53 #include "ecmascript/jspandafile/constpool_value.h"
54 #include "ecmascript/jspandafile/js_pandafile.h"
55 #include "ecmascript/jspandafile/js_pandafile_manager.h"
56 #include "ecmascript/jspandafile/quick_fix_manager.h"
57 #include "ecmascript/jspandafile/module_data_extractor.h"
58 #include "ecmascript/jspandafile/panda_file_translator.h"
59 #include "ecmascript/jspandafile/program_object.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/mem/concurrent_marker.h"
65 #include "ecmascript/mem/heap.h"
66 #include "ecmascript/mem/gc_stats.h"
67 #include "ecmascript/mem/mem.h"
68 #include "ecmascript/mem/space.h"
69 #include "ecmascript/mem/visitor.h"
70 #include "ecmascript/napi/include/dfx_jsnapi.h"
71 #include "ecmascript/taskpool/task.h"
72 #include "ecmascript/module/js_module_manager.h"
73 #include "ecmascript/object_factory.h"
74 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
75 #include "ecmascript/taskpool/taskpool.h"
76 #include "ecmascript/regexp/regexp_parser_cache.h"
77 #include "ecmascript/runtime_call_id.h"
78 #include "ecmascript/snapshot/mem/snapshot_env.h"
79 #include "ecmascript/snapshot/mem/snapshot.h"
80 #include "ecmascript/stubs/runtime_stubs.h"
81 #include "ecmascript/tagged_array-inl.h"
82 #include "ecmascript/tagged_dictionary.h"
83 #include "ecmascript/tagged_queue.h"
84 #include "ecmascript/tagged_queue.h"
85 #include "ecmascript/ts_types/ts_manager.h"
86 #include "ecmascript/require/js_cjs_module_cache.h"
87 #include "ecmascript/require/js_require_manager.h"
88 
89 namespace panda::ecmascript {
90 using RandomGenerator = base::RandomGenerator;
91 using PathHelper = base::PathHelper;
92 /* static */
Create(const JSRuntimeOptions & options,EcmaParamConfiguration & config)93 EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options, EcmaParamConfiguration &config)
94 {
95     JSRuntimeOptions newOptions = options;
96     // only define SUPPORT_ENABLE_ASM_INTERP can enable asm-interpreter
97 #if !defined(SUPPORT_ENABLE_ASM_INTERP)
98     newOptions.SetEnableAsmInterpreter(false);
99 #endif
100     auto vm = new EcmaVM(newOptions, config);
101     if (UNLIKELY(vm == nullptr)) {
102         LOG_ECMA(ERROR) << "Failed to create jsvm";
103         return nullptr;
104     }
105     auto jsThread = JSThread::Create(vm);
106     vm->thread_ = jsThread;
107     vm->Initialize();
108     return vm;
109 }
110 
111 // static
Destroy(EcmaVM * vm)112 bool EcmaVM::Destroy(EcmaVM *vm)
113 {
114     if (vm != nullptr) {
115         delete vm;
116         vm = nullptr;
117         return true;
118     }
119     return false;
120 }
121 
PreFork()122 void EcmaVM::PreFork()
123 {
124     heap_->CompactHeapBeforeFork();
125     heap_->AdjustSpaceSizeForAppSpawn();
126     heap_->GetReadOnlySpace()->SetReadOnly();
127     heap_->DisableParallelGC();
128 }
129 
PostFork()130 void EcmaVM::PostFork()
131 {
132     RandomGenerator::InitRandom();
133     heap_->SetHeapMode(HeapMode::SHARE);
134     GetAssociatedJSThread()->SetThreadId();
135     heap_->EnableParallelGC();
136 }
137 
EcmaVM(JSRuntimeOptions options,EcmaParamConfiguration config)138 EcmaVM::EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config)
139     : stringTable_(new EcmaStringTable(this)),
140       nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
141       heapRegionAllocator_(std::make_unique<HeapRegionAllocator>()),
142       chunk_(nativeAreaAllocator_.get()),
143       ecmaParamConfiguration_(std::move(config))
144 {
145     options_ = std::move(options);
146     icEnabled_ = options_.EnableIC();
147     optionalLogEnabled_ = options_.EnableOptionalLog();
148     snapshotFileName_ = options_.GetSnapshotFile().c_str();
149     frameworkAbcFileName_ = options_.GetFrameworkAbcFile().c_str();
150     options_.ParseAsmInterOption();
151 }
152 
ResetPGOProfiler()153 void EcmaVM::ResetPGOProfiler()
154 {
155     bool isEnablePGOProfiler = IsEnablePGOProfiler();
156     if (options_.IsWorker()) {
157         isEnablePGOProfiler = PGOProfilerManager::GetInstance()->IsEnable();
158     }
159     if (pgoProfiler_ == nullptr) {
160         pgoProfiler_ = PGOProfilerManager::GetInstance()->Build(this, isEnablePGOProfiler);
161     } else {
162         PGOProfilerManager::GetInstance()->Reset(pgoProfiler_, isEnablePGOProfiler);
163     }
164     thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
165 }
166 
IsEnablePGOProfiler() const167 bool EcmaVM::IsEnablePGOProfiler() const
168 {
169     return options_.GetEnableAsmInterpreter() && options_.IsEnablePGOProfiler();
170 }
171 
Initialize()172 bool EcmaVM::Initialize()
173 {
174     ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "EcmaVM::Initialize");
175     ResetPGOProfiler();
176     Taskpool::GetCurrentTaskpool()->Initialize();
177 #ifndef PANDA_TARGET_WINDOWS
178     RuntimeStubs::Initialize(thread_);
179 #endif
180     auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
181     regExpParserCache_ = new RegExpParserCache();
182     heap_ = new Heap(this);
183     heap_->Initialize();
184     gcStats_ = chunk_.New<GCStats>(heap_, options_.GetLongPauseTime());
185     factory_ = chunk_.New<ObjectFactory>(thread_, heap_);
186     if (UNLIKELY(factory_ == nullptr)) {
187         LOG_FULL(FATAL) << "alloc factory_ failed";
188         UNREACHABLE();
189     }
190     debuggerManager_ = chunk_.New<tooling::JsDebuggerManager>(this);
191     [[maybe_unused]] EcmaHandleScope scope(thread_);
192 
193     if (!options_.EnableSnapshotDeserialize()) {
194         LOG_ECMA(DEBUG) << "EcmaVM::Initialize run builtins";
195         JSHandle<JSHClass> hClassHandle = factory_->InitClassClass();
196         JSHandle<JSHClass> globalEnvClass = factory_->NewEcmaHClass(*hClassHandle,
197                                                                    GlobalEnv::SIZE,
198                                                                    JSType::GLOBAL_ENV);
199         globalConst->Init(thread_, *hClassHandle);
200         globalConstInitialized_ = true;
201         JSHandle<GlobalEnv> globalEnv = factory_->NewGlobalEnv(*globalEnvClass);
202         globalEnv->Init(thread_);
203         globalEnv_ = globalEnv.GetTaggedValue();
204         thread_->SetGlueGlobalEnv(reinterpret_cast<GlobalEnv *>(globalEnv.GetTaggedType()));
205         Builtins builtins;
206         builtins.Initialize(globalEnv, thread_);
207         if (!WIN_OR_MAC_OR_IOS_PLATFORM && options_.EnableSnapshotSerialize()) {
208             const CString fileName = "builtins.snapshot";
209             Snapshot snapshot(this);
210             snapshot.SerializeBuiltins(fileName);
211         }
212     } else {
213         const CString fileName = "builtins.snapshot";
214         Snapshot snapshot(this);
215         if (!WIN_OR_MAC_OR_IOS_PLATFORM) {
216             snapshot.Deserialize(SnapshotType::BUILTINS, fileName, true);
217         }
218         globalConst->InitSpecialForSnapshot();
219         Builtins builtins;
220         builtins.InitializeForSnapshot(thread_);
221         globalConstInitialized_ = true;
222     }
223 
224     SetupRegExpResultCache();
225     microJobQueue_ = factory_->NewMicroJobQueue().GetTaggedValue();
226     GenerateInternalNativeMethods();
227     thread_->SetGlobalObject(GetGlobalEnv()->GetGlobalObject());
228     moduleManager_ = new ModuleManager(this);
229     tsManager_ = new TSManager(this);
230     quickFixManager_ = new QuickFixManager();
231     snapshotEnv_ = new SnapshotEnv(this);
232     if (!WIN_OR_MAC_OR_IOS_PLATFORM) {
233         snapshotEnv_->Initialize();
234     }
235     aotFileManager_ = new AOTFileManager(this);
236     if (options_.GetEnableAsmInterpreter()) {
237         LoadStubFile();
238     }
239 
240     if (options_.GetEnableAsmInterpreter() && options_.WasAOTOutputFileSet()) {
241         AnFileDataManager::GetInstance()->SetEnable(true);
242         std::string aotFilename = options_.GetAOTOutputFile();
243         LoadAOTFiles(aotFilename);
244     }
245 
246     optCodeProfiler_ = new OptCodeProfiler();
247 
248     initialized_ = true;
249     return true;
250 }
251 
InitializeEcmaScriptRunStat()252 void EcmaVM::InitializeEcmaScriptRunStat()
253 {
254     // NOLINTNEXTLINE(modernize-avoid-c-arrays)
255     static const char *runtimeCallerNames[] = {
256 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
257 #define INTERPRETER_CALLER_NAME(name) "Interpreter::" #name,
258     INTERPRETER_CALLER_LIST(INTERPRETER_CALLER_NAME)  // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
259 #undef INTERPRETER_CALLER_NAME
260 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
261 #define BUILTINS_API_NAME(class, name) "BuiltinsApi::" #class "_" #name,
262     BUILTINS_API_LIST(BUILTINS_API_NAME)
263 #undef BUILTINS_API_NAME
264 #define ABSTRACT_OPERATION_NAME(class, name) "AbstractOperation::" #class "_" #name,
265     ABSTRACT_OPERATION_LIST(ABSTRACT_OPERATION_NAME)
266 #undef ABSTRACT_OPERATION_NAME
267 #define MEM_ALLOCATE_AND_GC_NAME(name) "Memory::" #name,
268     MEM_ALLOCATE_AND_GC_LIST(MEM_ALLOCATE_AND_GC_NAME)
269 #undef MEM_ALLOCATE_AND_GC_NAME
270 #define DEF_RUNTIME_ID(name) "Runtime::" #name,
271     RUNTIME_STUB_WITH_GC_LIST(DEF_RUNTIME_ID)
272 #undef DEF_RUNTIME_ID
273     };
274     static_assert(sizeof(runtimeCallerNames) == sizeof(const char *) * ecmascript::RUNTIME_CALLER_NUMBER,
275                   "Invalid runtime caller number");
276     runtimeStat_ = chunk_.New<EcmaRuntimeStat>(runtimeCallerNames, ecmascript::RUNTIME_CALLER_NUMBER);
277     if (UNLIKELY(runtimeStat_ == nullptr)) {
278         LOG_FULL(FATAL) << "alloc runtimeStat_ failed";
279         UNREACHABLE();
280     }
281 }
282 
SetRuntimeStatEnable(bool flag)283 void EcmaVM::SetRuntimeStatEnable(bool flag)
284 {
285     static uint64_t start = 0;
286     if (flag) {
287         start = PandaRuntimeTimer::Now();
288         if (runtimeStat_ == nullptr) {
289             InitializeEcmaScriptRunStat();
290         }
291     } else {
292         LOG_ECMA(INFO) << "Runtime State duration:" << PandaRuntimeTimer::Now() - start << "(ns)";
293         if (runtimeStat_->IsRuntimeStatEnabled()) {
294             runtimeStat_->Print();
295             runtimeStat_->ResetAllCount();
296         }
297     }
298     runtimeStat_->SetRuntimeStatEnabled(flag);
299 }
300 
~EcmaVM()301 EcmaVM::~EcmaVM()
302 {
303     initialized_ = false;
304 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
305     DFXJSNApi::StopCpuProfilerForFile(this);
306 #endif
307     heap_->WaitAllTasksFinished();
308     Taskpool::GetCurrentTaskpool()->Destroy(thread_->GetThreadId());
309 
310     if (runtimeStat_ != nullptr && runtimeStat_->IsRuntimeStatEnabled()) {
311         runtimeStat_->Print();
312     }
313 
314     if (optCodeProfiler_ != nullptr) {
315         delete optCodeProfiler_;
316         optCodeProfiler_ = nullptr;
317     }
318 
319     // clear c_address: c++ pointer delete
320     ClearBufferData();
321 
322     if (!isBundlePack_) {
323         const JSPandaFile *jsPandaFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(assetPath_);
324         if (jsPandaFile != nullptr) {
325             const_cast<JSPandaFile *>(jsPandaFile)->DeleteParsedConstpoolVM(this);
326         }
327     }
328     // clear icu cache
329     ClearIcuCache();
330 
331     if (gcStats_ != nullptr) {
332         if (options_.EnableGCStatsPrint()) {
333             gcStats_->PrintStatisticResult(true);
334         }
335         chunk_.Delete(gcStats_);
336         gcStats_ = nullptr;
337     }
338 
339     if (heap_ != nullptr) {
340         heap_->Destroy();
341         delete heap_;
342         heap_ = nullptr;
343     }
344 
345     if (regExpParserCache_ != nullptr) {
346         delete regExpParserCache_;
347         regExpParserCache_ = nullptr;
348     }
349 
350     if (debuggerManager_ != nullptr) {
351         chunk_.Delete(debuggerManager_);
352         debuggerManager_ = nullptr;
353     }
354 
355     if (factory_ != nullptr) {
356         chunk_.Delete(factory_);
357         factory_ = nullptr;
358     }
359 
360     if (stringTable_ != nullptr) {
361         delete stringTable_;
362         stringTable_ = nullptr;
363     }
364 
365     if (runtimeStat_ != nullptr) {
366         chunk_.Delete(runtimeStat_);
367         runtimeStat_ = nullptr;
368     }
369 
370     if (moduleManager_ != nullptr) {
371         delete moduleManager_;
372         moduleManager_ = nullptr;
373     }
374 
375     if (tsManager_ != nullptr) {
376         delete tsManager_;
377         tsManager_ = nullptr;
378     }
379 
380     if (quickFixManager_ != nullptr) {
381         delete quickFixManager_;
382         quickFixManager_ = nullptr;
383     }
384 
385     if (snapshotEnv_ != nullptr) {
386         delete snapshotEnv_;
387         snapshotEnv_ = nullptr;
388     }
389 
390     if (aotFileManager_ != nullptr) {
391         delete aotFileManager_;
392         aotFileManager_  = nullptr;
393     }
394 
395     if (thread_ != nullptr) {
396         delete thread_;
397         thread_ = nullptr;
398     }
399 
400     if (pgoProfiler_ != nullptr) {
401         PGOProfilerManager::GetInstance()->Destroy(pgoProfiler_);
402         pgoProfiler_ = nullptr;
403     }
404 }
405 
GetGlobalEnv() const406 JSHandle<GlobalEnv> EcmaVM::GetGlobalEnv() const
407 {
408     return JSHandle<GlobalEnv>(reinterpret_cast<uintptr_t>(&globalEnv_));
409 }
410 
GetMicroJobQueue() const411 JSHandle<job::MicroJobQueue> EcmaVM::GetMicroJobQueue() const
412 {
413     return JSHandle<job::MicroJobQueue>(reinterpret_cast<uintptr_t>(&microJobQueue_));
414 }
415 
FindCatchBlock(Method * method,uint32_t pc) const416 bool EcmaVM::FindCatchBlock(Method *method, uint32_t pc) const
417 {
418     uint32_t pcOffset = panda_file::INVALID_OFFSET;
419     if (thread_->IsAsmInterpreter()) {
420         pcOffset = InterpreterAssembly::FindCatchBlock(method, pc);
421     } else {
422         pcOffset = EcmaInterpreter::FindCatchBlock(method, pc);
423     }
424     return pcOffset != panda_file::INVALID_OFFSET;
425 }
426 
InvokeEcmaAotEntrypoint(JSHandle<JSFunction> mainFunc,JSHandle<JSTaggedValue> & thisArg,const JSPandaFile * jsPandaFile,std::string_view entryPoint)427 JSTaggedValue EcmaVM::InvokeEcmaAotEntrypoint(JSHandle<JSFunction> mainFunc, JSHandle<JSTaggedValue> &thisArg,
428                                               const JSPandaFile *jsPandaFile, std::string_view entryPoint)
429 {
430     aotFileManager_->SetAOTMainFuncEntry(mainFunc, jsPandaFile, entryPoint);
431     Method *method = mainFunc->GetCallTarget();
432     size_t actualNumArgs = method->GetNumArgs();
433     size_t argsNum = actualNumArgs + NUM_MANDATORY_JSFUNC_ARGS;
434     std::vector<JSTaggedType> args(argsNum, JSTaggedValue::Undefined().GetRawData());
435     args[0] = mainFunc.GetTaggedValue().GetRawData();
436     args[2] = thisArg.GetTaggedValue().GetRawData(); // 2: this
437     const JSTaggedType *prevFp = thread_->GetLastLeaveFrame();
438     // do not modify this log to INFO, this will call many times
439     LOG_ECMA(DEBUG) << "start to execute aot entry: " << entryPoint;
440     JSTaggedValue res = ExecuteAot(actualNumArgs, args.data(), prevFp, OptimizedEntryFrame::CallType::CALL_FUNC);
441     if (thread_->HasPendingException()) {
442         return thread_->GetException();
443     }
444     return res;
445 }
446 
ExecuteAot(size_t actualNumArgs,JSTaggedType * args,const JSTaggedType * prevFp,OptimizedEntryFrame::CallType callType)447 JSTaggedValue EcmaVM::ExecuteAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp,
448                                  OptimizedEntryFrame::CallType callType)
449 {
450     INTERPRETER_TRACE(thread_, ExecuteAot);
451     auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_JSFunctionEntry);
452     // do not modify this log to INFO, this will call many times
453     LOG_ECMA(DEBUG) << "start to execute aot entry: " << (void*)entry;
454     auto res = reinterpret_cast<JSFunctionEntryType>(entry)(thread_->GetGlueAddr(),
455                                                             actualNumArgs,
456                                                             args,
457                                                             reinterpret_cast<uintptr_t>(prevFp),
458                                                             static_cast<size_t>(callType));
459     return res;
460 }
461 
CheckStartCpuProfiler()462 void EcmaVM::CheckStartCpuProfiler()
463 {
464 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
465     if (profiler_ == nullptr && !options_.IsWorker() &&
466         options_.EnableCpuProfiler() && options_.GetArkBundleName().compare(bundleName_) == 0) {
467         std::string fileName = options_.GetArkBundleName() + ".cpuprofile";
468         if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
469             LOG_ECMA(ERROR) << "createFile failed " << fileName;
470         } else {
471             DFXJSNApi::StartCpuProfilerForFile(this, fileName);
472         }
473     }
474 #endif
475 }
476 
InvokeEcmaEntrypoint(const JSPandaFile * jsPandaFile,std::string_view entryPoint,bool excuteFromJob)477 Expected<JSTaggedValue, bool> EcmaVM::InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile, std::string_view entryPoint,
478                                                            bool excuteFromJob)
479 {
480     JSTaggedValue result;
481     [[maybe_unused]] EcmaHandleScope scope(thread_);
482     JSHandle<Program> program;
483     if (jsPandaFile != frameworkPandaFile_) {
484         program = JSPandaFileManager::GetInstance()->GenerateProgram(this, jsPandaFile, entryPoint);
485     } else {
486         program = JSHandle<Program>(thread_, frameworkProgram_);
487         frameworkProgram_ = JSTaggedValue::Hole();
488     }
489     if (program.IsEmpty()) {
490         LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed";
491         return Unexpected(false);
492     }
493     // for debugger
494     debuggerManager_->GetNotificationManager()->LoadModuleEvent(jsPandaFile->GetJSPandaFileDesc(), entryPoint);
495 
496     JSHandle<JSFunction> func = JSHandle<JSFunction>(thread_, program->GetMainFunction());
497     JSHandle<JSTaggedValue> global = GlobalEnv::Cast(globalEnv_.GetTaggedObject())->GetJSGlobalObject();
498     if (jsPandaFile->IsModule(thread_, entryPoint.data())) {
499         global = JSHandle<JSTaggedValue>(thread_, JSTaggedValue::Undefined());
500         CString moduleName = jsPandaFile->GetJSPandaFileDesc();
501         if (!jsPandaFile->IsBundlePack()) {
502             moduleName = entryPoint.data();
503         }
504         JSHandle<SourceTextModule> module = moduleManager_->HostGetImportedModule(moduleName);
505         func->SetModule(thread_, module);
506     } else {
507         // if it is Cjs at present, the module slot of the function is not used. We borrow it to store the recordName,
508         // which can avoid the problem of larger memory caused by the new slot
509         JSHandle<EcmaString> recordName =  factory_->NewFromUtf8(entryPoint.data());
510         func->SetModule(thread_, recordName);
511     }
512     CheckStartCpuProfiler();
513 
514     if (aotFileManager_->IsLoadMain(jsPandaFile, entryPoint.data())) {
515         thread_->SetPrintBCOffset(true);
516         EcmaRuntimeStatScope runtimeStatScope(this);
517         result = InvokeEcmaAotEntrypoint(func, global, jsPandaFile, entryPoint);
518     } else {
519         if (jsPandaFile->IsCjs(thread_, entryPoint.data())) {
520             if (!thread_->HasPendingException()) {
521                 CJSExecution(func, global, jsPandaFile);
522             }
523         } else {
524             JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
525             EcmaRuntimeCallInfo *info =
526                 EcmaInterpreter::NewRuntimeCallInfo(thread_, JSHandle<JSTaggedValue>(func), global, undefined, 0);
527             EcmaRuntimeStatScope runtimeStatScope(this);
528             EcmaInterpreter::Execute(info);
529         }
530     }
531     if (!thread_->HasPendingException()) {
532         job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
533     }
534 
535     // print exception information
536     if (!excuteFromJob && thread_->HasPendingException()) {
537         auto exception = thread_->GetException();
538         HandleUncaughtException(exception.GetTaggedObject());
539     }
540     return result;
541 }
542 
HasCachedConstpool(const JSPandaFile * jsPandaFile) const543 bool EcmaVM::HasCachedConstpool(const JSPandaFile *jsPandaFile) const
544 {
545     return cachedConstpools_.find(jsPandaFile) != cachedConstpools_.end();
546 }
547 
FindConstpool(const JSPandaFile * jsPandaFile,int32_t index)548 JSTaggedValue EcmaVM::FindConstpool(const JSPandaFile *jsPandaFile, int32_t index)
549 {
550     auto iter = cachedConstpools_.find(jsPandaFile);
551     if (iter == cachedConstpools_.end()) {
552         return JSTaggedValue::Hole();
553     }
554     auto constpoolIter = iter->second.find(index);
555     if (constpoolIter == iter->second.end()) {
556         return JSTaggedValue::Hole();
557     }
558     return constpoolIter->second;
559 }
560 
FindOrCreateConstPool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id)561 JSHandle<ConstantPool> EcmaVM::FindOrCreateConstPool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id)
562 {
563     panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id);
564     int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
565     JSTaggedValue constpool = FindConstpool(jsPandaFile, index);
566     if (constpool.IsHole()) {
567         JSHandle<ConstantPool> newConstpool = ConstantPool::CreateConstPool(this, jsPandaFile, id);
568         AddConstpool(jsPandaFile, newConstpool.GetTaggedValue(), index);
569         return newConstpool;
570     }
571 
572     return JSHandle<ConstantPool>(thread_, constpool);
573 }
574 
FindConstpools(const JSPandaFile * jsPandaFile)575 std::optional<std::reference_wrapper<CMap<int32_t, JSTaggedValue>>> EcmaVM::FindConstpools(
576     const JSPandaFile *jsPandaFile)
577 {
578     auto iter = cachedConstpools_.find(jsPandaFile);
579     if (iter == cachedConstpools_.end()) {
580         return std::nullopt;
581     }
582     return iter->second;
583 }
584 
CJSExecution(JSHandle<JSFunction> & func,JSHandle<JSTaggedValue> & thisArg,const JSPandaFile * jsPandaFile)585 void EcmaVM::CJSExecution(JSHandle<JSFunction> &func, JSHandle<JSTaggedValue> &thisArg,
586                           const JSPandaFile *jsPandaFile)
587 {
588     // create "module", "exports", "require", "filename", "dirname"
589     JSHandle<CjsModule> module = factory_->NewCjsModule();
590     JSHandle<JSTaggedValue> require = GetGlobalEnv()->GetCjsRequireFunction();
591     JSHandle<CjsExports> exports = factory_->NewCjsExports();
592     JSMutableHandle<JSTaggedValue> filename(thread_, JSTaggedValue::Undefined());
593     JSMutableHandle<JSTaggedValue> dirname(thread_, JSTaggedValue::Undefined());
594     if (jsPandaFile->IsBundlePack()) {
595         PathHelper::ResolveCurrentPath(thread_, dirname, filename, jsPandaFile);
596     } else {
597         filename.Update(JSFunction::Cast(func.GetTaggedValue().GetTaggedObject())->GetModule());
598         ASSERT(filename->IsString());
599         dirname.Update(PathHelper::ResolveDirPath(thread_, filename));
600     }
601     CJSInfo cjsInfo(module, require, exports, filename, dirname);
602     RequireManager::InitializeCommonJS(thread_, cjsInfo);
603 
604     // Execute main function
605     JSHandle<JSTaggedValue> undefined = thread_->GlobalConstants()->GetHandledUndefined();
606     EcmaRuntimeCallInfo *info =
607         EcmaInterpreter::NewRuntimeCallInfo(thread_,
608                                             JSHandle<JSTaggedValue>(func),
609                                             thisArg, undefined, 5); // 5 : argument numbers
610     RETURN_IF_ABRUPT_COMPLETION(thread_);
611     if (info == nullptr) {
612         LOG_ECMA(ERROR) << "CJSExecution Stack overflow!";
613         return;
614     }
615     info->SetCallArg(cjsInfo.exportsHdl.GetTaggedValue(),
616                      cjsInfo.requireHdl.GetTaggedValue(),
617                      cjsInfo.moduleHdl.GetTaggedValue(),
618                      cjsInfo.filenameHdl.GetTaggedValue(),
619                      cjsInfo.dirnameHdl.GetTaggedValue());
620     EcmaRuntimeStatScope runtimeStatScope(this);
621     EcmaInterpreter::Execute(info);
622     if (!thread_->HasPendingException()) {
623         job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
624     }
625 
626     if (!thread_->HasPendingException()) {
627         // Collecting module.exports : exports ---> module.exports --->Module._cache
628         RequireManager::CollectExecutedExp(thread_, cjsInfo);
629     }
630 }
631 
AddConstpool(const JSPandaFile * jsPandaFile,JSTaggedValue constpool,int32_t index)632 void EcmaVM::AddConstpool(const JSPandaFile *jsPandaFile, JSTaggedValue constpool, int32_t index)
633 {
634     ASSERT(constpool.IsConstantPool());
635     if (cachedConstpools_.find(jsPandaFile) == cachedConstpools_.end()) {
636         cachedConstpools_[jsPandaFile] = CMap<int32_t, JSTaggedValue>();
637     }
638     auto &constpoolMap = cachedConstpools_[jsPandaFile];
639     ASSERT(constpoolMap.find(index) == constpoolMap.end());
640 
641     constpoolMap.insert({index, constpool});
642 }
643 
GetAndClearEcmaUncaughtException() const644 JSHandle<JSTaggedValue> EcmaVM::GetAndClearEcmaUncaughtException() const
645 {
646     JSHandle<JSTaggedValue> exceptionHandle = GetEcmaUncaughtException();
647     thread_->ClearException();  // clear for ohos app
648     return exceptionHandle;
649 }
650 
GetEcmaUncaughtException() const651 JSHandle<JSTaggedValue> EcmaVM::GetEcmaUncaughtException() const
652 {
653     if (!thread_->HasPendingException()) {
654         return JSHandle<JSTaggedValue>();
655     }
656     JSHandle<JSTaggedValue> exceptionHandle(thread_, thread_->GetException());
657     return exceptionHandle;
658 }
659 
EnableUserUncaughtErrorHandler()660 void EcmaVM::EnableUserUncaughtErrorHandler()
661 {
662     isUncaughtExceptionRegistered_ = true;
663 }
664 
HandleUncaughtException(TaggedObject * exception)665 void EcmaVM::HandleUncaughtException(TaggedObject *exception)
666 {
667     if (isUncaughtExceptionRegistered_) {
668         return;
669     }
670     [[maybe_unused]] EcmaHandleScope handleScope(thread_);
671     JSHandle<JSTaggedValue> exceptionHandle(thread_, JSTaggedValue(exception));
672     // if caught exceptionHandle type is JSError
673     thread_->ClearException();
674     if (exceptionHandle->IsJSError()) {
675         PrintJSErrorInfo(exceptionHandle);
676         if (thread_->IsPrintBCOffset() && exceptionBCList_.size() != 0) {
677             for (auto info : exceptionBCList_) {
678                 LOG_ECMA(ERROR) << "Exception at function " << info.first << ": " << info.second;
679             }
680         }
681         return;
682     }
683     JSHandle<EcmaString> result = JSTaggedValue::ToString(thread_, exceptionHandle);
684     CString string = ConvertToString(*result);
685     LOG_NO_TAG(ERROR) << string;
686 }
687 
PrintJSErrorInfo(const JSHandle<JSTaggedValue> & exceptionInfo)688 void EcmaVM::PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo)
689 {
690     JSHandle<JSTaggedValue> nameKey = thread_->GlobalConstants()->GetHandledNameString();
691     JSHandle<EcmaString> name(JSObject::GetProperty(thread_, exceptionInfo, nameKey).GetValue());
692     JSHandle<JSTaggedValue> msgKey = thread_->GlobalConstants()->GetHandledMessageString();
693     JSHandle<EcmaString> msg(JSObject::GetProperty(thread_, exceptionInfo, msgKey).GetValue());
694     JSHandle<JSTaggedValue> stackKey = thread_->GlobalConstants()->GetHandledStackString();
695     JSHandle<EcmaString> stack(JSObject::GetProperty(thread_, exceptionInfo, stackKey).GetValue());
696 
697     CString nameBuffer = ConvertToString(*name);
698     CString msgBuffer = ConvertToString(*msg);
699     CString stackBuffer = ConvertToString(*stack);
700     LOG_NO_TAG(ERROR) << nameBuffer << ": " << msgBuffer << "\n" << stackBuffer;
701 }
702 
ProcessNativeDelete(const WeakRootVisitor & visitor)703 void EcmaVM::ProcessNativeDelete(const WeakRootVisitor &visitor)
704 {
705     auto iter = nativePointerList_.begin();
706     while (iter != nativePointerList_.end()) {
707         JSNativePointer *object = *iter;
708         auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
709         if (fwd == nullptr) {
710             object->Destroy();
711             iter = nativePointerList_.erase(iter);
712         } else {
713             ++iter;
714         }
715     }
716 
717     auto iterator = cachedConstpools_.begin();
718     while (iterator != cachedConstpools_.end()) {
719         auto &constpools = iterator->second;
720         auto constpoolIter = constpools.begin();
721         while (constpoolIter != constpools.end()) {
722             JSTaggedValue constpoolVal = constpoolIter->second;
723             if (constpoolVal.IsHeapObject()) {
724                 TaggedObject *obj = constpoolVal.GetTaggedObject();
725                 auto fwd = visitor(obj);
726                 if (fwd == nullptr) {
727                     constpoolIter = constpools.erase(constpoolIter);
728                     continue;
729                 }
730             }
731             ++constpoolIter;
732         }
733         if (constpools.size() == 0) {
734             JSPandaFileManager::RemoveJSPandaFile(const_cast<JSPandaFile *>(iterator->first));
735             iterator = cachedConstpools_.erase(iterator);
736         } else {
737             ++iterator;
738         }
739     }
740 }
ProcessReferences(const WeakRootVisitor & visitor)741 void EcmaVM::ProcessReferences(const WeakRootVisitor &visitor)
742 {
743     if (regExpParserCache_ != nullptr) {
744         regExpParserCache_->Clear();
745     }
746     heap_->ResetNativeBindingSize();
747     // array buffer
748     auto iter = nativePointerList_.begin();
749     while (iter != nativePointerList_.end()) {
750         JSNativePointer *object = *iter;
751         auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
752         if (fwd == nullptr) {
753             object->Destroy();
754             iter = nativePointerList_.erase(iter);
755             continue;
756         }
757         heap_->IncreaseNativeBindingSize(JSNativePointer::Cast(fwd));
758         if (fwd != reinterpret_cast<TaggedObject *>(object)) {
759             *iter = JSNativePointer::Cast(fwd);
760         }
761         ++iter;
762     }
763 
764     // program maps
765     auto iterator = cachedConstpools_.begin();
766     while (iterator != cachedConstpools_.end()) {
767         auto &constpools = iterator->second;
768         auto constpoolIter = constpools.begin();
769         while (constpoolIter != constpools.end()) {
770             JSTaggedValue constpoolVal = constpoolIter->second;
771             if (constpoolVal.IsHeapObject()) {
772                 TaggedObject *obj = constpoolVal.GetTaggedObject();
773                 auto fwd = visitor(obj);
774                 if (fwd == nullptr) {
775                     constpoolIter = constpools.erase(constpoolIter);
776                     continue;
777                 } else if (fwd != obj) {
778                     constpoolIter->second = JSTaggedValue(fwd);
779                 }
780             }
781             ++constpoolIter;
782         }
783         if (constpools.size() == 0) {
784             JSPandaFileManager::RemoveJSPandaFile(const_cast<JSPandaFile *>(iterator->first));
785             iterator = cachedConstpools_.erase(iterator);
786         } else {
787             ++iterator;
788         }
789     }
790 }
791 
PushToNativePointerList(JSNativePointer * array)792 void EcmaVM::PushToNativePointerList(JSNativePointer *array)
793 {
794     nativePointerList_.emplace_back(array);
795 }
796 
RemoveFromNativePointerList(JSNativePointer * array)797 void EcmaVM::RemoveFromNativePointerList(JSNativePointer *array)
798 {
799     auto iter = std::find(nativePointerList_.begin(), nativePointerList_.end(), array);
800     if (iter != nativePointerList_.end()) {
801         JSNativePointer *object = *iter;
802         object->Destroy();
803         nativePointerList_.erase(iter);
804     }
805 }
806 
ClearBufferData()807 void EcmaVM::ClearBufferData()
808 {
809     for (auto iter : nativePointerList_) {
810         iter->Destroy();
811     }
812     nativePointerList_.clear();
813 
814     cachedConstpools_.clear();
815     internalNativeMethods_.clear();
816     WorkerList_.clear();
817 }
818 
ExecutePromisePendingJob()819 bool EcmaVM::ExecutePromisePendingJob()
820 {
821     if (isProcessingPendingJob_) {
822         LOG_ECMA(DEBUG) << "EcmaVM::ExecutePromisePendingJob can not reentrant";
823         return false;
824     }
825     if (!thread_->HasPendingException()) {
826         isProcessingPendingJob_ = true;
827         job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
828         isProcessingPendingJob_ = false;
829         return true;
830     }
831     return false;
832 }
833 
CollectGarbage(TriggerGCType gcType) const834 void EcmaVM::CollectGarbage(TriggerGCType gcType) const
835 {
836     heap_->CollectGarbage(gcType);
837 }
838 
StartHeapTracking(HeapTracker * tracker)839 void EcmaVM::StartHeapTracking(HeapTracker *tracker)
840 {
841     heap_->StartHeapTracking(tracker);
842 }
843 
StopHeapTracking()844 void EcmaVM::StopHeapTracking()
845 {
846     heap_->StopHeapTracking();
847 }
848 
Iterate(const RootVisitor & v,const RootRangeVisitor & rv)849 void EcmaVM::Iterate(const RootVisitor &v, const RootRangeVisitor &rv)
850 {
851     v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&globalEnv_)));
852     v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&microJobQueue_)));
853     v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&regexpCache_)));
854     v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&frameworkProgram_)));
855     rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&internalNativeMethods_.front())),
856         ObjectSlot(ToUintPtr(&internalNativeMethods_.back()) + JSTaggedValue::TaggedTypeSize()));
857     moduleManager_->Iterate(v);
858     tsManager_->Iterate(v);
859     aotFileManager_->Iterate(v);
860     if (!WIN_OR_MAC_OR_IOS_PLATFORM) {
861         snapshotEnv_->Iterate(v);
862     }
863 }
864 
SetGlobalEnv(GlobalEnv * global)865 void EcmaVM::SetGlobalEnv(GlobalEnv *global)
866 {
867     ASSERT(global != nullptr);
868     globalEnv_ = JSTaggedValue(global);
869 }
870 
SetMicroJobQueue(job::MicroJobQueue * queue)871 void EcmaVM::SetMicroJobQueue(job::MicroJobQueue *queue)
872 {
873     ASSERT(queue != nullptr);
874     microJobQueue_ = JSTaggedValue(queue);
875 }
876 
SetupRegExpResultCache()877 void EcmaVM::SetupRegExpResultCache()
878 {
879     regexpCache_ = builtins::RegExpExecResultCache::CreateCacheTable(thread_);
880 }
881 
LoadStubFile()882 void EcmaVM::LoadStubFile()
883 {
884     std::string stubFile = options_.GetStubFile();
885     aotFileManager_->LoadStubFile(stubFile);
886 }
887 
LoadAOTFiles(const std::string & aotFileName)888 void EcmaVM::LoadAOTFiles(const std::string& aotFileName)
889 {
890     std::string anFile = aotFileName + AOTFileManager::FILE_EXTENSION_AN;
891     aotFileManager_->LoadAnFile(anFile);
892 
893     std::string aiFile = aotFileName + AOTFileManager::FILE_EXTENSION_AI;
894     aotFileManager_->LoadAiFile(aiFile);
895 }
896 
897 #if !WIN_OR_MAC_OR_IOS_PLATFORM
DeleteHeapProfile()898 void EcmaVM::DeleteHeapProfile()
899 {
900     if (heapProfile_ == nullptr) {
901         return;
902     }
903     const_cast<NativeAreaAllocator *>(GetNativeAreaAllocator())->Delete(heapProfile_);
904     heapProfile_ = nullptr;
905 }
906 
GetOrNewHeapProfile()907 HeapProfilerInterface *EcmaVM::GetOrNewHeapProfile()
908 {
909     if (heapProfile_ != nullptr) {
910         return heapProfile_;
911     }
912     heapProfile_ = const_cast<NativeAreaAllocator *>(GetNativeAreaAllocator())->New<HeapProfiler>(this);
913     ASSERT(heapProfile_ != nullptr);
914     return heapProfile_;
915 }
916 #endif
917 
918 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
919 void *EcmaVM::InternalMethodTable[] = {
920     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsBoundFunction),
921     reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsProxy),
922     reinterpret_cast<void *>(builtins::BuiltinsObject::CreateDataPropertyOnObjectFunctions),
923     reinterpret_cast<void *>(builtins::BuiltinsCollator::AnonymousCollator),
924     reinterpret_cast<void *>(builtins::BuiltinsDateTimeFormat::AnonymousDateTimeFormat),
925     reinterpret_cast<void *>(builtins::BuiltinsNumberFormat::NumberFormatInternalFormatNumber),
926     reinterpret_cast<void *>(builtins::BuiltinsProxy::InvalidateProxyFunction),
927     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitFulfilled),
928     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitRejected),
929     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ResolveElementFunction),
930     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Resolve),
931     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Reject),
932     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Executor),
933     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AnyRejectElementFunction),
934     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledResolveElementFunction),
935     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledRejectElementFunction),
936     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ThenFinally),
937     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::CatchFinally),
938     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::valueThunkFunction),
939     reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::throwerFunction),
940     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorFulfilledFunc),
941     reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorRejectedFunc),
942     reinterpret_cast<void *>(JSAsyncFromSyncIterator::AsyncFromSyncIterUnwarpFunction)
943 };
944 
GenerateInternalNativeMethods()945 void EcmaVM::GenerateInternalNativeMethods()
946 {
947     size_t length = static_cast<size_t>(MethodIndex::METHOD_END);
948     for (size_t i = 0; i < length; i++) {
949         uint32_t numArgs = 2;  // function object and this
950         auto method = factory_->NewMethod(nullptr);
951         method->SetNativePointer(InternalMethodTable[i]);
952         method->SetNativeBit(true);
953         method->SetNumArgsWithCallField(numArgs);
954         method->SetFunctionKind(FunctionKind::NORMAL_FUNCTION);
955         internalNativeMethods_.emplace_back(method.GetTaggedValue());
956     }
957 }
958 
GetMethodByIndex(MethodIndex idx)959 JSTaggedValue EcmaVM::GetMethodByIndex(MethodIndex idx)
960 {
961     auto index = static_cast<uint8_t>(idx);
962     ASSERT(index < internalNativeMethods_.size());
963     return internalNativeMethods_[index];
964 }
965 
TriggerConcurrentCallback(JSTaggedValue result,JSTaggedValue hint)966 void EcmaVM::TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint)
967 {
968     if (concurrentCallback_ == nullptr) {
969         LOG_ECMA(INFO) << "Only trigger concurrent callback in taskpool thread";
970         return;
971     }
972 
973     if (result.IsJSPromise()) {
974         // Async concurrent will return Promise
975         auto promise = JSPromise::Cast(result.GetTaggedObject());
976         if (promise->GetPromiseState() == PromiseState::PENDING) {
977             LOG_ECMA(ERROR) << "Promise is in pending state, don't return";
978             return;
979         }
980         result = promise->GetPromiseResult();
981     }
982 
983     auto ret = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, result));
984     auto data = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, hint));
985     concurrentCallback_(ret, data, concurrentData_);
986 }
987 }  // namespace panda::ecmascript
988