• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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.h"
20 #include "ecmascript/builtins/builtins_regexp.h"
21 #include "ecmascript/class_linker/panda_file_translator.h"
22 #include "ecmascript/ecma_macros.h"
23 #include "ecmascript/jspandafile/program_object-inl.h"
24 #include "ecmascript/cpu_profiler/cpu_profiler.h"
25 #include "ecmascript/ecma_module.h"
26 #include "ecmascript/ecma_string_table.h"
27 #include "ecmascript/global_dictionary.h"
28 #include "ecmascript/global_env.h"
29 #include "ecmascript/global_env_constants-inl.h"
30 #include "ecmascript/global_env_constants.h"
31 #include "ecmascript/internal_call_params.h"
32 #include "ecmascript/jobs/micro_job_queue.h"
33 #include "ecmascript/jspandafile/js_pandafile.h"
34 #include "ecmascript/jspandafile/js_pandafile_manager.h"
35 #include "ecmascript/js_arraybuffer.h"
36 #include "ecmascript/js_for_in_iterator.h"
37 #include "ecmascript/js_invoker.h"
38 #include "ecmascript/js_native_pointer.h"
39 #include "ecmascript/js_thread.h"
40 #include "ecmascript/mem/concurrent_marker.h"
41 #include "ecmascript/mem/heap.h"
42 #include "ecmascript/object_factory.h"
43 #include "ecmascript/platform/platform.h"
44 #include "ecmascript/regexp/regexp_parser_cache.h"
45 #include "ecmascript/runtime_call_id.h"
46 #include "ecmascript/runtime_trampolines.h"
47 #include "ecmascript/snapshot/mem/slot_bit.h"
48 #include "ecmascript/snapshot/mem/snapshot.h"
49 #include "ecmascript/snapshot/mem/snapshot_serialize.h"
50 #include "ecmascript/symbol_table.h"
51 #include "ecmascript/tagged_array-inl.h"
52 #include "ecmascript/tagged_dictionary.h"
53 #include "ecmascript/tagged_queue-inl.h"
54 #include "ecmascript/tagged_queue.h"
55 #include "ecmascript/template_map.h"
56 #include "ecmascript/tooling/interface/js_debugger_manager.h"
57 #include "ecmascript/ts_types/ts_loader.h"
58 #include "ecmascript/vmstat/runtime_stat.h"
59 #include "libpandafile/file.h"
60 
61 namespace panda::ecmascript {
62 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
63 static const std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0";
64 JSRuntimeOptions EcmaVM::options_;  // NOLINT(fuchsia-statically-constructed-objects)
65 
66 /* static */
Create(const JSRuntimeOptions & options)67 EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options)
68 {
69     auto runtime = Runtime::GetCurrent();
70     auto vm = runtime->GetInternalAllocator()->New<EcmaVM>(options);
71     if (UNLIKELY(vm == nullptr)) {
72         LOG_ECMA(ERROR) << "Failed to create jsvm";
73         return nullptr;
74     }
75     auto jsThread = JSThread::Create(runtime, vm);
76     vm->thread_ = jsThread;
77     vm->Initialize();
78     return vm;
79 }
80 
81 // static
Destroy(PandaVM * vm)82 bool EcmaVM::Destroy(PandaVM *vm)
83 {
84     if (vm != nullptr) {
85         auto runtime = Runtime::GetCurrent();
86         runtime->GetInternalAllocator()->Delete(vm);
87         return true;
88     }
89     return false;
90 }
91 
92 // static
Create(Runtime * runtime)93 Expected<EcmaVM *, CString> EcmaVM::Create(Runtime *runtime)
94 {
95     EcmaVM *vm = runtime->GetInternalAllocator()->New<EcmaVM>();
96     auto jsThread = ecmascript::JSThread::Create(runtime, vm);
97     vm->thread_ = jsThread;
98     return vm;
99 }
100 
101 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
EcmaVM()102 EcmaVM::EcmaVM() : EcmaVM(EcmaVM::GetJSOptions())
103 {
104     isTestMode_ = true;
105 }
106 
EcmaVM(JSRuntimeOptions options)107 EcmaVM::EcmaVM(JSRuntimeOptions options)
108     : stringTable_(new EcmaStringTable(this)),
109       nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
110       heapRegionAllocator_(std::make_unique<HeapRegionAllocator>()),
111       chunk_(nativeAreaAllocator_.get()),
112       arrayBufferDataList_(&chunk_),
113       frameworkProgramMethods_(&chunk_),
114       nativeMethodMaps_(&chunk_)
115 {
116     options_ = std::move(options);
117     icEnable_ = options_.IsIcEnable();
118     optionalLogEnabled_ = options_.IsEnableOptionalLog();
119     snapshotSerializeEnable_ = options_.IsSnapshotSerializeEnabled();
120     if (!snapshotSerializeEnable_) {
121         snapshotDeserializeEnable_ = options_.IsSnapshotDeserializeEnabled();
122     }
123     snapshotFileName_ = options_.GetSnapshotFile();
124     frameworkAbcFileName_ = options_.GetFrameworkAbcFile();
125 
126     debuggerManager_ = chunk_.New<tooling::JsDebuggerManager>();
127 }
128 
Initialize()129 bool EcmaVM::Initialize()
130 {
131     ECMA_BYTRACE_NAME(BYTRACE_TAG_ARK, "EcmaVM::Initialize");
132     Platform::GetCurrentPlatform()->Initialize();
133     RuntimeTrampolines::InitializeRuntimeTrampolines(thread_);
134 
135     auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
136     regExpParserCache_ = new RegExpParserCache();
137     heap_ = new Heap(this);
138     heap_->Initialize();
139     gcStats_ = chunk_.New<GCStats>(heap_);
140     factory_ = chunk_.New<ObjectFactory>(thread_, heap_);
141     if (UNLIKELY(factory_ == nullptr)) {
142         LOG_ECMA(FATAL) << "alloc factory_ failed";
143         UNREACHABLE();
144     }
145 
146     [[maybe_unused]] EcmaHandleScope scope(thread_);
147     if (!snapshotDeserializeEnable_ || !VerifyFilePath(snapshotFileName_)) {
148         LOG_ECMA(DEBUG) << "EcmaVM::Initialize run builtins";
149 
150         JSHandle<JSHClass> dynClassClassHandle =
151             factory_->NewEcmaDynClassClass(nullptr, JSHClass::SIZE, JSType::HCLASS);
152         JSHClass *dynclass = reinterpret_cast<JSHClass *>(dynClassClassHandle.GetTaggedValue().GetTaggedObject());
153         dynclass->SetClass(dynclass);
154         JSHandle<JSHClass> globalEnvClass =
155             factory_->NewEcmaDynClass(*dynClassClassHandle, GlobalEnv::SIZE, JSType::GLOBAL_ENV);
156 
157         JSHandle<GlobalEnv> globalEnvHandle = factory_->NewGlobalEnv(*globalEnvClass);
158         globalEnv_ = globalEnvHandle.GetTaggedValue();
159         auto globalEnv = GlobalEnv::Cast(globalEnv_.GetTaggedObject());
160 
161         // init global env
162         globalConst->InitRootsClass(thread_, *dynClassClassHandle);
163         globalConst->InitGlobalConstant(thread_);
164         globalEnv->SetEmptyArray(thread_, factory_->NewEmptyArray());
165         globalEnv->SetEmptyLayoutInfo(thread_, factory_->CreateLayoutInfo(0));
166         globalEnv->SetRegisterSymbols(thread_, SymbolTable::Create(thread_));
167         globalEnv->SetGlobalRecord(thread_, GlobalDictionary::Create(thread_));
168         JSTaggedValue emptyStr = thread_->GlobalConstants()->GetEmptyString();
169         stringTable_->InternEmptyString(EcmaString::Cast(emptyStr.GetTaggedObject()));
170         globalEnv->SetEmptyTaggedQueue(thread_, factory_->NewTaggedQueue(0));
171         globalEnv->SetTemplateMap(thread_, TemplateMap::Create(thread_));
172         globalEnv->SetRegisterSymbols(GetJSThread(), SymbolTable::Create(GetJSThread()));
173 #ifdef ECMASCRIPT_ENABLE_STUB_AOT
174         std::string moduleFile = options_.GetStubModuleFile();
175         thread_->LoadStubModule(moduleFile.c_str());
176 #endif
177         SetupRegExpResultCache();
178         microJobQueue_ = factory_->NewMicroJobQueue().GetTaggedValue();
179         {
180             Builtins builtins;
181             builtins.Initialize(globalEnvHandle, thread_);
182         }
183     } else {
184         LOG_ECMA(DEBUG) << "EcmaVM::Initialize run snapshot";
185         SnapShot snapShot(this);
186         std::unique_ptr<const panda_file::File> pf = snapShot.DeserializeGlobalEnvAndProgram(snapshotFileName_);
187         frameworkPandaFile_ = JSPandaFileManager::GetInstance()->CreateJSPandaFile(pf.release(), frameworkAbcFileName_);
188         globalConst->InitGlobalUndefined();
189     }
190 
191     thread_->SetGlobalObject(GetGlobalEnv()->GetGlobalObject());
192     moduleManager_ = new ModuleManager(this);
193     tsLoader_ = new TSLoader(this);
194     debuggerManager_->Initialize();
195     InitializeFinish();
196     return true;
197 }
198 
InitializeEcmaScriptRunStat()199 void EcmaVM::InitializeEcmaScriptRunStat()
200 {
201     // NOLINTNEXTLINE(modernize-avoid-c-arrays)
202     static const char *runtimeCallerNames[] = {
203 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
204 #define INTERPRETER_CALLER_NAME(name) "Interpreter::" #name,
205     INTERPRETER_CALLER_LIST(INTERPRETER_CALLER_NAME)  // NOLINTNEXTLINE(bugprone-suspicious-missing-comma)
206 #undef INTERPRETER_CALLER_NAME
207 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
208 #define BUILTINS_API_NAME(class, name) "BuiltinsApi::" #class "_" #name,
209     BUITINS_API_LIST(BUILTINS_API_NAME)
210 #undef BUILTINS_API_NAME
211 #define ABSTRACT_OPERATION_NAME(class, name) "AbstractOperation::" #class "_" #name,
212     ABSTRACT_OPERATION_LIST(ABSTRACT_OPERATION_NAME)
213 #undef ABSTRACT_OPERATION_NAME
214 #define MEM_ALLOCATE_AND_GC_NAME(name) "Memory::" #name,
215     MEM_ALLOCATE_AND_GC_LIST(MEM_ALLOCATE_AND_GC_NAME)
216 #undef MEM_ALLOCATE_AND_GC_NAME
217     };
218     static_assert(sizeof(runtimeCallerNames) == sizeof(const char *) * ecmascript::RUNTIME_CALLER_NUMBER,
219                   "Invalid runtime caller number");
220     runtimeStat_ = chunk_.New<EcmaRuntimeStat>(runtimeCallerNames, ecmascript::RUNTIME_CALLER_NUMBER);
221     if (UNLIKELY(runtimeStat_ == nullptr)) {
222         LOG_ECMA(FATAL) << "alloc runtimeStat_ failed";
223         UNREACHABLE();
224     }
225 }
226 
SetRuntimeStatEnable(bool flag)227 void EcmaVM::SetRuntimeStatEnable(bool flag)
228 {
229     if (flag) {
230         if (runtimeStat_ == nullptr) {
231             InitializeEcmaScriptRunStat();
232         }
233     } else {
234         if (runtimeStatEnabled_) {
235             runtimeStat_->Print();
236             runtimeStat_->ResetAllCount();
237         }
238     }
239     runtimeStatEnabled_ = flag;
240 }
241 
InitializeFinish()242 bool EcmaVM::InitializeFinish()
243 {
244     vmInitialized_ = true;
245     return true;
246 }
247 
~EcmaVM()248 EcmaVM::~EcmaVM()
249 {
250     vmInitialized_ = false;
251     Platform::GetCurrentPlatform()->Destroy();
252     ClearNativeMethodsData();
253 
254     if (runtimeStat_ != nullptr && runtimeStatEnabled_) {
255         runtimeStat_->Print();
256     }
257 
258     // clear c_address: c++ pointer delete
259     ClearBufferData();
260 
261     // clear icu cache
262     ClearIcuCache();
263 
264     if (gcStats_ != nullptr) {
265         if (options_.IsEnableGCStatsPrint()) {
266             gcStats_->PrintStatisticResult(true);
267         }
268         chunk_.Delete(gcStats_);
269         gcStats_ = nullptr;
270     }
271 
272     if (heap_ != nullptr) {
273         heap_->Destroy();
274         delete heap_;
275         heap_ = nullptr;
276     }
277 
278     delete regExpParserCache_;
279     regExpParserCache_ = nullptr;
280 
281     if (debuggerManager_ != nullptr) {
282         chunk_.Delete(debuggerManager_);
283         debuggerManager_ = nullptr;
284     }
285 
286     if (factory_ != nullptr) {
287         chunk_.Delete(factory_);
288         factory_ = nullptr;
289     }
290 
291     if (stringTable_ != nullptr) {
292         delete stringTable_;
293         stringTable_ = nullptr;
294     }
295 
296     if (runtimeStat_ != nullptr) {
297         chunk_.Delete(runtimeStat_);
298         runtimeStat_ = nullptr;
299     }
300 
301     if (moduleManager_ != nullptr) {
302         delete moduleManager_;
303         moduleManager_ = nullptr;
304     }
305 
306     if (tsLoader_ != nullptr) {
307         delete tsLoader_;
308         tsLoader_ = nullptr;
309     }
310 
311     if (thread_ != nullptr) {
312         delete thread_;
313         thread_ = nullptr;
314     }
315 
316     frameworkProgramMethods_.clear();
317 }
318 
ExecuteFromPf(const std::string & filename,std::string_view entryPoint,const std::vector<std::string> & args,bool isModule)319 bool EcmaVM::ExecuteFromPf(const std::string &filename, std::string_view entryPoint,
320                            const std::vector<std::string> &args, bool isModule)
321 {
322     const JSPandaFile *jsPandaFile = nullptr;
323     if (frameworkPandaFile_ == nullptr || !IsFrameworkPandaFile(filename)) {
324         jsPandaFile = JSPandaFileManager::GetInstance()->LoadPfAbc(filename);
325         if (jsPandaFile == nullptr) {
326             return false;
327         }
328     } else {
329         jsPandaFile = frameworkPandaFile_;
330     }
331     return Execute(jsPandaFile, entryPoint, args);
332 }
333 
CollectInfoOfPandaFile(const std::string & filename,std::string_view entryPoint,std::vector<BytecodeTranslationInfo> * infoList,const panda_file::File * & pf)334 bool EcmaVM::CollectInfoOfPandaFile(const std::string &filename, std::string_view entryPoint,
335                                     std::vector<BytecodeTranslationInfo> *infoList, const panda_file::File *&pf)
336 {
337     const JSPandaFile *jsPandaFile;
338     if (frameworkPandaFile_ == nullptr || !IsFrameworkPandaFile(filename)) {
339         jsPandaFile = JSPandaFileManager::GetInstance()->LoadPfAbc(filename);
340         if (jsPandaFile == nullptr) {
341             return false;
342         }
343     } else {
344         jsPandaFile = frameworkPandaFile_;
345     }
346 
347     // Get ClassName and MethodName
348     size_t pos = entryPoint.find_last_of("::");
349     if (pos == std::string_view::npos) {
350         LOG_ECMA(ERROR) << "EntryPoint:" << entryPoint << " is illegal";
351         return false;
352     }
353     CString methodName(entryPoint.substr(pos + 1));
354 
355     PandaFileTranslator translator(this, jsPandaFile);
356     translator.TranslateAndCollectPandaFile(methodName, infoList);
357     return true;
358 }
359 
ExecuteFromBuffer(const void * buffer,size_t size,std::string_view entryPoint,const std::vector<std::string> & args,const std::string & filename)360 bool EcmaVM::ExecuteFromBuffer(const void *buffer, size_t size, std::string_view entryPoint,
361                                const std::vector<std::string> &args, const std::string &filename)
362 {
363     // Get ClassName and MethodName
364     size_t pos = entryPoint.find_last_of("::");
365     if (pos == std::string_view::npos) {
366         LOG_ECMA(ERROR) << "EntryPoint:" << entryPoint << " is illegal";
367         return false;
368     }
369     CString methodName(entryPoint.substr(pos + 1));
370     const JSPandaFile *jsPandaFile = JSPandaFileManager::GetInstance()->LoadBufferAbc(filename, buffer, size);
371     if (jsPandaFile == nullptr) {
372         return false;
373     }
374     InvokeEcmaEntrypoint(jsPandaFile, methodName, args);
375     return true;
376 }
377 
Execute(const JSPandaFile * jsPandaFile,std::string_view entryPoint,const std::vector<std::string> & args)378 bool EcmaVM::Execute(const JSPandaFile *jsPandaFile, std::string_view entryPoint, const std::vector<std::string> &args)
379 {
380     // Get ClassName and MethodName
381     size_t pos = entryPoint.find_last_of("::");
382     if (pos == std::string_view::npos) {
383         LOG_ECMA(ERROR) << "EntryPoint:" << entryPoint << " is illegal";
384         return false;
385     }
386     CString methodName(entryPoint.substr(pos + 1));
387     // For Ark application startup
388     InvokeEcmaEntrypoint(jsPandaFile, methodName, args);
389     return true;
390 }
391 
GetGlobalEnv() const392 JSHandle<GlobalEnv> EcmaVM::GetGlobalEnv() const
393 {
394     return JSHandle<GlobalEnv>(reinterpret_cast<uintptr_t>(&globalEnv_));
395 }
396 
GetMicroJobQueue() const397 JSHandle<job::MicroJobQueue> EcmaVM::GetMicroJobQueue() const
398 {
399     return JSHandle<job::MicroJobQueue>(reinterpret_cast<uintptr_t>(&microJobQueue_));
400 }
401 
GetMethodForNativeFunction(const void * func)402 JSMethod *EcmaVM::GetMethodForNativeFunction(const void *func)
403 {
404     // signature: any foo(any function_obj, any this)
405     uint32_t accessFlags = ACC_PUBLIC | ACC_STATIC | ACC_FINAL | ACC_NATIVE;
406     uint32_t numArgs = 2;  // function object and this
407 
408     auto iter = nativeMethodMaps_.find(func);
409     if (iter != nativeMethodMaps_.end()) {
410         return iter->second;
411     }
412     auto method = chunk_.New<JSMethod>(nullptr, panda_file::File::EntityId(0), panda_file::File::EntityId(0),
413                                        accessFlags, numArgs, nullptr);
414     method->SetNativePointer(const_cast<void *>(func));
415     method->SetNativeBit(true);
416 
417     nativeMethodMaps_.emplace(func, method);
418     return method;
419 }
420 
FindConstpool(const JSPandaFile * jsPandaFile)421 JSTaggedValue EcmaVM::FindConstpool(const JSPandaFile *jsPandaFile)
422 {
423     auto iter = pandaFileWithConstpool_.find(jsPandaFile);
424     if (iter == pandaFileWithConstpool_.end()) {
425         return JSTaggedValue::Hole();
426     }
427     return iter->second;
428 }
429 
SetConstpool(const JSPandaFile * jsPandaFile,JSTaggedValue constpool)430 void EcmaVM::SetConstpool(const JSPandaFile *jsPandaFile, JSTaggedValue constpool)
431 {
432     ASSERT(constpool.IsTaggedArray());
433     ASSERT(pandaFileWithConstpool_.find(jsPandaFile) == pandaFileWithConstpool_.end());
434 
435     pandaFileWithConstpool_[jsPandaFile] = constpool;
436 }
437 
RedirectMethod(const panda_file::File & pf)438 void EcmaVM::RedirectMethod(const panda_file::File &pf)
439 {
440     for (auto method : frameworkProgramMethods_) {
441         method->SetPandaFile(&pf);
442     }
443 }
444 
InvokeEntrypointImpl(Method * entrypoint,const std::vector<std::string> & args)445 Expected<int, Runtime::Error> EcmaVM::InvokeEntrypointImpl(Method *entrypoint, const std::vector<std::string> &args)
446 {
447     // For testcase startup
448     const panda_file::File *file = entrypoint->GetPandaFile();
449     const JSPandaFile *jsPandaFile = JSPandaFileManager::GetInstance()->GetJSPandaFile(file);
450     ASSERT(jsPandaFile != nullptr);
451     return InvokeEcmaEntrypoint(jsPandaFile, utf::Mutf8AsCString(entrypoint->GetName().data), args);
452 }
453 
InvokeEcmaEntrypoint(const JSPandaFile * jsPandaFile,const CString & methodName,const std::vector<std::string> & args)454 Expected<int, Runtime::Error> EcmaVM::InvokeEcmaEntrypoint(const JSPandaFile *jsPandaFile,
455                                                            [[maybe_unused]] const CString &methodName,
456                                                            const std::vector<std::string> &args)
457 {
458     [[maybe_unused]] EcmaHandleScope scope(thread_);
459     JSHandle<Program> program;
460     if (snapshotSerializeEnable_) {
461         program = JSPandaFileManager::GetInstance()->GenerateProgram(this, jsPandaFile);
462 
463         auto index = jsPandaFile->GetJSPandaFileDesc().find(frameworkAbcFileName_);
464         if (index != CString::npos) {
465             LOG_ECMA(DEBUG) << "snapShot MakeSnapShotProgramObject abc " << jsPandaFile->GetJSPandaFileDesc();
466             SnapShot snapShot(this);
467             snapShot.MakeSnapShotProgramObject(*program, jsPandaFile->GetPandaFile(), snapshotFileName_);
468         }
469     } else {
470         if (jsPandaFile != frameworkPandaFile_) {
471             program = JSPandaFileManager::GetInstance()->GenerateProgram(this, jsPandaFile);
472         } else {
473             program = JSHandle<Program>(thread_, frameworkProgram_);
474             RedirectMethod(*jsPandaFile->GetPandaFile());
475         }
476     }
477 
478     if (program.IsEmpty()) {
479         LOG_ECMA(ERROR) << "program is empty, invoke entrypoint failed";
480         return Unexpected(Runtime::Error::PANDA_FILE_LOAD_ERROR);
481     }
482     // for debugger
483     debuggerManager_->GetNotificationManager()->LoadModuleEvent(jsPandaFile->GetJSPandaFileDesc());
484 
485     JSHandle<JSFunction> func = JSHandle<JSFunction>(thread_, program->GetMainFunction());
486     JSHandle<JSTaggedValue> global = GlobalEnv::Cast(globalEnv_.GetTaggedObject())->GetJSGlobalObject();
487     JSHandle<JSTaggedValue> newTarget(thread_, JSTaggedValue::Undefined());
488     JSHandle<TaggedArray> jsargs = factory_->NewTaggedArray(args.size());
489     uint32_t i = 0;
490     for (const std::string &str : args) {
491         JSHandle<JSTaggedValue> strobj(factory_->NewFromStdString(str));
492         jsargs->Set(thread_, i++, strobj);
493     }
494 
495     InternalCallParams *params = thread_->GetInternalCallParams();
496     params->MakeArgList(*jsargs);
497     JSRuntimeOptions options = this->GetJSOptions();
498     if (options.IsEnableCpuProfiler()) {
499         CpuProfiler *profiler = CpuProfiler::GetInstance();
500         profiler->CpuProfiler::StartCpuProfiler(this, "");
501         panda::ecmascript::InvokeJsFunction(thread_, func, global, newTarget, params);
502         profiler->CpuProfiler::StopCpuProfiler();
503     } else {
504         panda::ecmascript::InvokeJsFunction(thread_, func, global, newTarget, params);
505     }
506     if (!thread_->HasPendingException()) {
507         job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
508     }
509 
510     // print exception information
511     if (thread_->HasPendingException()) {
512         auto exception = thread_->GetException();
513         HandleUncaughtException(exception.GetTaggedObject());
514     }
515     return 0;
516 }
517 
IsFrameworkPandaFile(std::string_view filename) const518 bool EcmaVM::IsFrameworkPandaFile(std::string_view filename) const
519 {
520     return filename.size() >= frameworkAbcFileName_.size() &&
521            filename.substr(filename.size() - frameworkAbcFileName_.size()) == frameworkAbcFileName_;
522 }
523 
GetAndClearEcmaUncaughtException() const524 JSHandle<JSTaggedValue> EcmaVM::GetAndClearEcmaUncaughtException() const
525 {
526     JSHandle<JSTaggedValue> exceptionHandle = GetEcmaUncaughtException();
527     thread_->ClearException();  // clear for ohos app
528     return exceptionHandle;
529 }
530 
GetEcmaUncaughtException() const531 JSHandle<JSTaggedValue> EcmaVM::GetEcmaUncaughtException() const
532 {
533     if (thread_->GetException().IsHole()) {
534         return JSHandle<JSTaggedValue>();
535     }
536     JSHandle<JSTaggedValue> exceptionHandle(thread_, thread_->GetException());
537     return exceptionHandle;
538 }
539 
EnableUserUncaughtErrorHandler()540 void EcmaVM::EnableUserUncaughtErrorHandler()
541 {
542     isUncaughtExceptionRegistered_ = true;
543 }
544 
HandleUncaughtException(ObjectHeader * exception)545 void EcmaVM::HandleUncaughtException(ObjectHeader *exception)
546 {
547     if (isUncaughtExceptionRegistered_) {
548         return;
549     }
550     [[maybe_unused]] EcmaHandleScope handle_scope(thread_);
551     JSHandle<JSTaggedValue> exceptionHandle(thread_, JSTaggedValue(exception));
552     // if caught exceptionHandle type is JSError
553     thread_->ClearException();
554     if (exceptionHandle->IsJSError()) {
555         PrintJSErrorInfo(exceptionHandle);
556         return;
557     }
558     JSHandle<EcmaString> result = JSTaggedValue::ToString(thread_, exceptionHandle);
559     CString string = ConvertToString(*result);
560     LOG(ERROR, RUNTIME) << string;
561 }
562 
PrintJSErrorInfo(const JSHandle<JSTaggedValue> & exceptionInfo)563 void EcmaVM::PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo)
564 {
565     JSHandle<JSTaggedValue> nameKey = thread_->GlobalConstants()->GetHandledNameString();
566     JSHandle<EcmaString> name(JSObject::GetProperty(thread_, exceptionInfo, nameKey).GetValue());
567     JSHandle<JSTaggedValue> msgKey = thread_->GlobalConstants()->GetHandledMessageString();
568     JSHandle<EcmaString> msg(JSObject::GetProperty(thread_, exceptionInfo, msgKey).GetValue());
569     JSHandle<JSTaggedValue> stackKey = thread_->GlobalConstants()->GetHandledStackString();
570     JSHandle<EcmaString> stack(JSObject::GetProperty(thread_, exceptionInfo, stackKey).GetValue());
571 
572     CString nameBuffer = ConvertToString(*name);
573     CString msgBuffer = ConvertToString(*msg);
574     CString stackBuffer = ConvertToString(*stack);
575     LOG(ERROR, RUNTIME) << nameBuffer << ": " << msgBuffer << "\n" << stackBuffer;
576 }
577 
ProcessNativeDelete(const WeakRootVisitor & v0)578 void EcmaVM::ProcessNativeDelete(const WeakRootVisitor &v0)
579 {
580     auto iter = arrayBufferDataList_.begin();
581     while (iter != arrayBufferDataList_.end()) {
582         JSNativePointer *object = *iter;
583         auto fwd = v0(reinterpret_cast<TaggedObject *>(object));
584         if (fwd == nullptr) {
585             object->Destroy();
586             iter = arrayBufferDataList_.erase(iter);
587         } else {
588             ++iter;
589         }
590     }
591 }
ProcessReferences(const WeakRootVisitor & v0)592 void EcmaVM::ProcessReferences(const WeakRootVisitor &v0)
593 {
594     if (regExpParserCache_ != nullptr) {
595         regExpParserCache_->Clear();
596     }
597 
598     // array buffer
599     for (auto iter = arrayBufferDataList_.begin(); iter != arrayBufferDataList_.end();) {
600         JSNativePointer *object = *iter;
601         auto fwd = v0(reinterpret_cast<TaggedObject *>(object));
602         if (fwd == nullptr) {
603             object->Destroy();
604             iter = arrayBufferDataList_.erase(iter);
605             continue;
606         }
607         if (fwd != reinterpret_cast<TaggedObject *>(object)) {
608             *iter = JSNativePointer::Cast(fwd);
609         }
610         ++iter;
611     }
612 
613     // framework program
614     if (!frameworkProgram_.IsHole()) {
615         auto fwd = v0(frameworkProgram_.GetTaggedObject());
616         if (fwd == nullptr) {
617             frameworkProgram_ = JSTaggedValue::Undefined();
618         } else if (fwd != frameworkProgram_.GetTaggedObject()) {
619             frameworkProgram_ = JSTaggedValue(fwd);
620         }
621     }
622 
623     for (auto iter = pandaFileWithConstpool_.begin(); iter != pandaFileWithConstpool_.end();) {
624         auto object = iter->second;
625         if (object.IsObject()) {
626             TaggedObject *obj = object.GetTaggedObject();
627             auto fwd = v0(obj);
628             if (fwd == nullptr) {
629                 iter = pandaFileWithConstpool_.erase(iter);
630                 continue;
631             } else if (fwd != obj) {
632                 iter->second = JSTaggedValue(fwd);
633             }
634         }
635         ++iter;
636     }
637 }
638 
PushToArrayDataList(JSNativePointer * array)639 void EcmaVM::PushToArrayDataList(JSNativePointer *array)
640 {
641     if (std::find(arrayBufferDataList_.begin(), arrayBufferDataList_.end(), array) != arrayBufferDataList_.end()) {
642         return;
643     }
644     arrayBufferDataList_.emplace_back(array);
645 }
646 
RemoveArrayDataList(JSNativePointer * array)647 void EcmaVM::RemoveArrayDataList(JSNativePointer *array)
648 {
649     auto iter = std::find(arrayBufferDataList_.begin(), arrayBufferDataList_.end(), array);
650     if (iter != arrayBufferDataList_.end()) {
651         arrayBufferDataList_.erase(iter);
652     }
653 }
654 
VerifyFilePath(const CString & filePath) const655 bool EcmaVM::VerifyFilePath(const CString &filePath) const
656 {
657     if (filePath.size() > PATH_MAX) {
658         return false;
659     }
660 
661     CVector<char> resolvedPath(PATH_MAX);
662     auto result = realpath(filePath.c_str(), resolvedPath.data());
663     if (result == nullptr) {
664         return false;
665     }
666     std::ifstream file(resolvedPath.data());
667     if (!file.good()) {
668         return false;
669     }
670     file.close();
671     return true;
672 }
673 
ClearBufferData()674 void EcmaVM::ClearBufferData()
675 {
676     for (auto iter : arrayBufferDataList_) {
677         iter->Destroy();
678     }
679     arrayBufferDataList_.clear();
680 
681     pandaFileWithConstpool_.clear();
682 
683     if (frameworkPandaFile_) {
684         delete frameworkPandaFile_;
685         frameworkPandaFile_ = nullptr;
686     }
687 }
688 
ExecutePromisePendingJob() const689 bool EcmaVM::ExecutePromisePendingJob() const
690 {
691     thread_local bool isProcessing = false;
692     if (!isProcessing && !thread_->HasPendingException()) {
693         isProcessing = true;
694         job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue());
695         isProcessing = false;
696         return true;
697     }
698     return false;
699 }
700 
CollectGarbage(TriggerGCType gcType) const701 void EcmaVM::CollectGarbage(TriggerGCType gcType) const
702 {
703     heap_->CollectGarbage(gcType);
704 }
705 
StartHeapTracking(HeapTracker * tracker)706 void EcmaVM::StartHeapTracking(HeapTracker *tracker)
707 {
708     heap_->StartHeapTracking(tracker);
709 }
710 
StopHeapTracking()711 void EcmaVM::StopHeapTracking()
712 {
713     heap_->StopHeapTracking();
714 }
715 
Iterate(const RootVisitor & v)716 void EcmaVM::Iterate(const RootVisitor &v)
717 {
718     v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&globalEnv_)));
719     v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&microJobQueue_)));
720     v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&regexpCache_)));
721     moduleManager_->Iterate(v);
722     tsLoader_->Iterate(v);
723 }
724 
SetGlobalEnv(GlobalEnv * global)725 void EcmaVM::SetGlobalEnv(GlobalEnv *global)
726 {
727     ASSERT(global != nullptr);
728     globalEnv_ = JSTaggedValue(global);
729 }
730 
SetMicroJobQueue(job::MicroJobQueue * queue)731 void EcmaVM::SetMicroJobQueue(job::MicroJobQueue *queue)
732 {
733     ASSERT(queue != nullptr);
734     microJobQueue_ = JSTaggedValue(queue);
735 }
736 
GetModuleByName(JSHandle<JSTaggedValue> moduleName)737 JSHandle<JSTaggedValue> EcmaVM::GetModuleByName(JSHandle<JSTaggedValue> moduleName)
738 {
739     // only used in testcase, pandaFileWithProgram_ only one item. this interface will delete
740     const JSPandaFile *currentJSPandaFile = nullptr;
741     JSPandaFileManager::GetInstance()->EnumerateJSPandaFiles([&currentJSPandaFile](const JSPandaFile *jsPandaFile) {
742         currentJSPandaFile = jsPandaFile;
743         return false;
744     });
745     ASSERT(currentJSPandaFile != nullptr);
746     CString currentPathFile = currentJSPandaFile->GetJSPandaFileDesc();
747     CString relativeFile = ConvertToString(EcmaString::Cast(moduleName->GetTaggedObject()));
748 
749     // generate full path
750     CString abcPath = moduleManager_->GenerateAmiPath(currentPathFile, relativeFile);
751 
752     // Uniform module name
753     JSHandle<EcmaString> abcModuleName = factory_->NewFromString(abcPath);
754 
755     JSHandle<JSTaggedValue> module = moduleManager_->GetModule(thread_, JSHandle<JSTaggedValue>::Cast(abcModuleName));
756     if (module->IsUndefined()) {
757         std::string file = base::StringHelper::ToStdString(abcModuleName.GetObject<EcmaString>());
758         std::vector<std::string> argv;
759         ExecuteModule(file, ENTRY_POINTER, argv);
760         module = moduleManager_->GetModule(thread_, JSHandle<JSTaggedValue>::Cast(abcModuleName));
761     }
762     return module;
763 }
764 
ExecuteModule(const std::string & moduleFile,std::string_view entryPoint,const std::vector<std::string> & args)765 void EcmaVM::ExecuteModule(const std::string &moduleFile, std::string_view entryPoint,
766                            const std::vector<std::string> &args)
767 {
768     moduleManager_->SetCurrentExportModuleName(moduleFile);
769     // Update Current Module
770     EcmaVM::ExecuteFromPf(moduleFile, entryPoint, args, true);
771     // Restore Current Module
772     moduleManager_->RestoreCurrentExportModuleName();
773 }
774 
ClearNativeMethodsData()775 void EcmaVM::ClearNativeMethodsData()
776 {
777     for (auto iter : nativeMethodMaps_) {
778         chunk_.Delete(iter.second);
779     }
780     nativeMethodMaps_.clear();
781 }
782 
SetupRegExpResultCache()783 void EcmaVM::SetupRegExpResultCache()
784 {
785     regexpCache_ = builtins::RegExpExecResultCache::CreateCacheTable(thread_);
786 }
787 }  // namespace panda::ecmascript
788