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 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
38 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
39 #endif
40 #if !WIN_OR_MAC_OR_IOS_PLATFORM
41 #include "ecmascript/dfx/hprof/heap_profiler.h"
42 #include "ecmascript/dfx/hprof/heap_profiler_interface.h"
43 #endif
44 #include "ecmascript/compiler/aot_file/an_file_data_manager.h"
45 #include "ecmascript/compiler/aot_file/aot_file_manager.h"
46 #include "ecmascript/debugger/js_debugger_manager.h"
47 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
48 #include "ecmascript/dfx/vmstat/function_call_timer.h"
49 #include "ecmascript/dfx/vmstat/opt_code_profiler.h"
50 #include "ecmascript/dfx/vmstat/runtime_stat.h"
51 #include "ecmascript/ecma_context.h"
52 #include "ecmascript/ecma_string_table.h"
53 #include "ecmascript/global_env.h"
54 #include "ecmascript/global_env_constants-inl.h"
55 #include "ecmascript/global_env_constants.h"
56 #include "ecmascript/interpreter/interpreter-inl.h"
57 #include "ecmascript/jobs/micro_job_queue.h"
58 #include "ecmascript/js_arraybuffer.h"
59 #include "ecmascript/js_for_in_iterator.h"
60 #include "ecmascript/js_native_pointer.h"
61 #include "ecmascript/js_thread.h"
62 #include "ecmascript/jspandafile/constpool_value.h"
63 #include "ecmascript/jspandafile/js_pandafile.h"
64 #include "ecmascript/jspandafile/js_pandafile_manager.h"
65 #include "ecmascript/jspandafile/panda_file_translator.h"
66 #include "ecmascript/jspandafile/program_object.h"
67 #include "ecmascript/mem/concurrent_marker.h"
68 #include "ecmascript/mem/gc_stats.h"
69 #include "ecmascript/mem/heap.h"
70 #include "ecmascript/mem/mem.h"
71 #include "ecmascript/mem/space.h"
72 #include "ecmascript/mem/visitor.h"
73 #include "ecmascript/module/js_module_manager.h"
74 #include "ecmascript/module/module_data_extractor.h"
75 #include "ecmascript/object_factory.h"
76 #include "ecmascript/patch/quick_fix_manager.h"
77 #include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
78 #include "ecmascript/regexp/regexp_parser_cache.h"
79 #include "ecmascript/runtime_call_id.h"
80 #include "ecmascript/snapshot/mem/snapshot.h"
81 #include "ecmascript/snapshot/mem/snapshot_env.h"
82 #include "ecmascript/stubs/runtime_stubs.h"
83 #include "ecmascript/tagged_array-inl.h"
84 #include "ecmascript/tagged_dictionary.h"
85 #include "ecmascript/tagged_queue.h"
86 #include "ecmascript/tagged_queue.h"
87 #include "ecmascript/taskpool/task.h"
88 #include "ecmascript/taskpool/taskpool.h"
89 #include "ecmascript/ts_types/ts_manager.h"
90
91 namespace panda::ecmascript {
92 using RandomGenerator = base::RandomGenerator;
93 AOTFileManager *JsStackInfo::loader = nullptr;
94 /* static */
Create(const JSRuntimeOptions & options,EcmaParamConfiguration & config)95 EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options, EcmaParamConfiguration &config)
96 {
97 JSRuntimeOptions newOptions = options;
98 // only define SUPPORT_ENABLE_ASM_INTERP can enable asm-interpreter
99 #if !defined(SUPPORT_ENABLE_ASM_INTERP)
100 newOptions.SetEnableAsmInterpreter(false);
101 #endif
102 auto vm = new EcmaVM(newOptions, config);
103 if (UNLIKELY(vm == nullptr)) {
104 LOG_ECMA(ERROR) << "Failed to create jsvm";
105 return nullptr;
106 }
107 auto jsThread = JSThread::Create(vm);
108 vm->thread_ = jsThread;
109 vm->Initialize();
110 JsStackInfo::loader = vm->GetJSThread()->GetCurrentEcmaContext()->GetAOTFileManager();
111 #if defined(__aarch64__) && !defined(PANDA_TARGET_MACOS) && !defined(PANDA_TARGET_IOS)
112 if (SetThreadInfoCallback != nullptr) {
113 SetThreadInfoCallback(CrashCallback);
114 }
115 #endif
116 return vm;
117 }
118
119 // static
Destroy(EcmaVM * vm)120 bool EcmaVM::Destroy(EcmaVM *vm)
121 {
122 if (vm != nullptr) {
123 delete vm;
124 vm = nullptr;
125 return true;
126 }
127 return false;
128 }
129
PreFork()130 void EcmaVM::PreFork()
131 {
132 heap_->CompactHeapBeforeFork();
133 heap_->AdjustSpaceSizeForAppSpawn();
134 heap_->GetReadOnlySpace()->SetReadOnly();
135 heap_->DisableParallelGC();
136 }
137
PostFork()138 void EcmaVM::PostFork()
139 {
140 RandomGenerator::InitRandom();
141 heap_->SetHeapMode(HeapMode::SHARE);
142 GetAssociatedJSThread()->SetThreadId();
143 heap_->EnableParallelGC();
144 }
145
EcmaVM(JSRuntimeOptions options,EcmaParamConfiguration config)146 EcmaVM::EcmaVM(JSRuntimeOptions options, EcmaParamConfiguration config)
147 : stringTable_(new EcmaStringTable(this)),
148 nativeAreaAllocator_(std::make_unique<NativeAreaAllocator>()),
149 heapRegionAllocator_(std::make_unique<HeapRegionAllocator>()),
150 chunk_(nativeAreaAllocator_.get()),
151 ecmaParamConfiguration_(std::move(config))
152 {
153 options_ = std::move(options);
154 icEnabled_ = options_.EnableIC();
155 optionalLogEnabled_ = options_.EnableOptionalLog();
156 options_.ParseAsmInterOption();
157 }
158
InitializePGOProfiler()159 void EcmaVM::InitializePGOProfiler()
160 {
161 bool isEnablePGOProfiler = IsEnablePGOProfiler();
162 if (pgoProfiler_ == nullptr) {
163 pgoProfiler_ = PGOProfilerManager::GetInstance()->Build(this, isEnablePGOProfiler);
164 }
165 thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
166 }
167
ResetPGOProfiler()168 void EcmaVM::ResetPGOProfiler()
169 {
170 if (pgoProfiler_ != nullptr) {
171 bool isEnablePGOProfiler = IsEnablePGOProfiler();
172 PGOProfilerManager::GetInstance()->Reset(pgoProfiler_, isEnablePGOProfiler);
173 thread_->SetPGOProfilerEnable(isEnablePGOProfiler);
174 thread_->CheckOrSwitchPGOStubs();
175 }
176 }
177
IsEnablePGOProfiler() const178 bool EcmaVM::IsEnablePGOProfiler() const
179 {
180 if (options_.IsWorker()) {
181 return PGOProfilerManager::GetInstance()->IsEnable();
182 }
183 return options_.GetEnableAsmInterpreter() && options_.IsEnablePGOProfiler();
184 }
185
Initialize()186 bool EcmaVM::Initialize()
187 {
188 ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "EcmaVM::Initialize");
189 InitializePGOProfiler();
190 Taskpool::GetCurrentTaskpool()->Initialize();
191 #ifndef PANDA_TARGET_WINDOWS
192 RuntimeStubs::Initialize(thread_);
193 #endif
194 heap_ = new Heap(this);
195 heap_->Initialize();
196 gcStats_ = chunk_.New<GCStats>(heap_, options_.GetLongPauseTime());
197 factory_ = chunk_.New<ObjectFactory>(thread_, heap_);
198 if (UNLIKELY(factory_ == nullptr)) {
199 LOG_FULL(FATAL) << "alloc factory_ failed";
200 UNREACHABLE();
201 }
202 debuggerManager_ = chunk_.New<tooling::JsDebuggerManager>(this);
203 auto context = new EcmaContext(thread_);
204 thread_->PushContext(context);
205 [[maybe_unused]] EcmaHandleScope scope(thread_);
206 context->Initialize();
207 thread_->SetGlueGlobalEnv(reinterpret_cast<GlobalEnv *>(context->GetGlobalEnv().GetTaggedType()));
208 thread_->SetGlobalObject(GetGlobalEnv()->GetGlobalObject());
209 thread_->SetCurrentEcmaContext(context);
210
211 GenerateInternalNativeMethods();
212 quickFixManager_ = new QuickFixManager();
213 snapshotEnv_ = new SnapshotEnv(this);
214 if (!WIN_OR_MAC_OR_IOS_PLATFORM) {
215 snapshotEnv_->Initialize();
216 }
217 if (options_.GetEnableAsmInterpreter()) {
218 thread_->GetCurrentEcmaContext()->LoadStubFile();
219 }
220
221 callTimer_ = new FunctionCallTimer();
222
223 initialized_ = true;
224 return true;
225 }
226
~EcmaVM()227 EcmaVM::~EcmaVM()
228 {
229 initialized_ = false;
230 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
231 DFXJSNApi::StopCpuProfilerForFile(this);
232 #endif
233 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
234 DeleteHeapProfile();
235 #endif
236 heap_->WaitAllTasksFinished();
237 Taskpool::GetCurrentTaskpool()->Destroy(thread_->GetThreadId());
238
239 if (pgoProfiler_ != nullptr) {
240 PGOProfilerManager::GetInstance()->Destroy(pgoProfiler_);
241 pgoProfiler_ = nullptr;
242 }
243
244 #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER
245 DumpCallTimeInfo();
246 #endif
247
248 // clear c_address: c++ pointer delete
249 ClearBufferData();
250 if (!isBundlePack_) {
251 std::shared_ptr<JSPandaFile> jsPandaFile = JSPandaFileManager::GetInstance()->FindJSPandaFile(assetPath_);
252 if (jsPandaFile != nullptr) {
253 jsPandaFile->DeleteParsedConstpoolVM(this);
254 }
255 }
256
257 if (gcStats_ != nullptr) {
258 if (options_.EnableGCStatsPrint()) {
259 gcStats_->PrintStatisticResult();
260 }
261 chunk_.Delete(gcStats_);
262 gcStats_ = nullptr;
263 }
264
265 if (heap_ != nullptr) {
266 heap_->Destroy();
267 delete heap_;
268 heap_ = nullptr;
269 }
270
271 if (debuggerManager_ != nullptr) {
272 chunk_.Delete(debuggerManager_);
273 debuggerManager_ = nullptr;
274 }
275
276 if (factory_ != nullptr) {
277 chunk_.Delete(factory_);
278 factory_ = nullptr;
279 }
280
281 if (stringTable_ != nullptr) {
282 delete stringTable_;
283 stringTable_ = nullptr;
284 }
285
286 if (quickFixManager_ != nullptr) {
287 delete quickFixManager_;
288 quickFixManager_ = nullptr;
289 }
290
291 if (snapshotEnv_ != nullptr) {
292 delete snapshotEnv_;
293 snapshotEnv_ = nullptr;
294 }
295
296 if (callTimer_ != nullptr) {
297 delete callTimer_;
298 callTimer_ = nullptr;
299 }
300
301 if (thread_ != nullptr) {
302 delete thread_;
303 thread_ = nullptr;
304 }
305 }
306
GetGlobalEnv() const307 JSHandle<GlobalEnv> EcmaVM::GetGlobalEnv() const
308 {
309 return thread_->GetCurrentEcmaContext()->GetGlobalEnv();
310 }
311
FastCallAot(size_t actualNumArgs,JSTaggedType * args,const JSTaggedType * prevFp)312 JSTaggedValue EcmaVM::FastCallAot(size_t actualNumArgs, JSTaggedType *args, const JSTaggedType *prevFp)
313 {
314 INTERPRETER_TRACE(thread_, ExecuteAot);
315 auto entry = thread_->GetRTInterface(kungfu::RuntimeStubCSigns::ID_OptimizedFastCallEntry);
316 // do not modify this log to INFO, this will call many times
317 LOG_ECMA(DEBUG) << "start to execute aot entry: " << (void*)entry;
318 auto res = reinterpret_cast<FastCallAotEntryType>(entry)(thread_->GetGlueAddr(),
319 actualNumArgs,
320 args,
321 reinterpret_cast<uintptr_t>(prevFp));
322 return res;
323 }
324
CheckStartCpuProfiler()325 void EcmaVM::CheckStartCpuProfiler()
326 {
327 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
328 if (options_.EnableCpuProfilerColdStartMainThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
329 !options_.IsWorker() && profiler_ == nullptr) {
330 std::string fileName = options_.GetArkBundleName() + ".cpuprofile";
331 if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
332 LOG_ECMA(ERROR) << "createFile failed " << fileName;
333 return;
334 } else {
335 DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
336 return;
337 }
338 }
339
340 if (options_.EnableCpuProfilerColdStartWorkerThread() && options_.GetArkBundleName().compare(bundleName_) == 0 &&
341 options_.IsWorker() && profiler_ == nullptr) {
342 std::string fileName = options_.GetArkBundleName() + "_"
343 + std::to_string(thread_->GetThreadId()) + ".cpuprofile";
344 if (!builtins::BuiltinsArkTools::CreateFile(fileName)) {
345 LOG_ECMA(ERROR) << "createFile failed " << fileName;
346 return;
347 } else {
348 DFXJSNApi::StartCpuProfilerForFile(this, fileName, CpuProfiler::INTERVAL_OF_INNER_START);
349 return;
350 }
351 }
352 #endif
353 }
354
GetAndClearEcmaUncaughtException() const355 JSHandle<JSTaggedValue> EcmaVM::GetAndClearEcmaUncaughtException() const
356 {
357 JSHandle<JSTaggedValue> exceptionHandle = GetEcmaUncaughtException();
358 thread_->ClearException(); // clear for ohos app
359 return exceptionHandle;
360 }
361
GetEcmaUncaughtException() const362 JSHandle<JSTaggedValue> EcmaVM::GetEcmaUncaughtException() const
363 {
364 if (!thread_->HasPendingException()) {
365 return JSHandle<JSTaggedValue>();
366 }
367 JSHandle<JSTaggedValue> exceptionHandle(thread_, thread_->GetException());
368 return exceptionHandle;
369 }
370
PrintJSErrorInfo(const JSHandle<JSTaggedValue> & exceptionInfo) const371 void EcmaVM::PrintJSErrorInfo(const JSHandle<JSTaggedValue> &exceptionInfo) const
372 {
373 EcmaContext::PrintJSErrorInfo(thread_, exceptionInfo);
374 }
375
ProcessNativeDelete(const WeakRootVisitor & visitor)376 void EcmaVM::ProcessNativeDelete(const WeakRootVisitor &visitor)
377 {
378 auto iter = nativePointerList_.begin();
379 while (iter != nativePointerList_.end()) {
380 JSNativePointer *object = *iter;
381 auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
382 if (fwd == nullptr) {
383 object->Destroy();
384 iter = nativePointerList_.erase(iter);
385 } else {
386 ++iter;
387 }
388 }
389 thread_->GetCurrentEcmaContext()->ProcessNativeDelete(visitor);
390 }
391
ProcessReferences(const WeakRootVisitor & visitor)392 void EcmaVM::ProcessReferences(const WeakRootVisitor &visitor)
393 {
394 if (thread_->GetCurrentEcmaContext()->GetRegExpParserCache() != nullptr) {
395 thread_->GetCurrentEcmaContext()->GetRegExpParserCache()->Clear();
396 }
397 heap_->ResetNativeBindingSize();
398 // array buffer
399 auto iter = nativePointerList_.begin();
400 while (iter != nativePointerList_.end()) {
401 JSNativePointer *object = *iter;
402 auto fwd = visitor(reinterpret_cast<TaggedObject *>(object));
403 if (fwd == nullptr) {
404 object->Destroy();
405 iter = nativePointerList_.erase(iter);
406 continue;
407 }
408 heap_->IncreaseNativeBindingSize(JSNativePointer::Cast(fwd));
409 if (fwd != reinterpret_cast<TaggedObject *>(object)) {
410 *iter = JSNativePointer::Cast(fwd);
411 }
412 ++iter;
413 }
414 thread_->GetCurrentEcmaContext()->ProcessReferences(visitor);
415 }
416
PushToNativePointerList(JSNativePointer * array)417 void EcmaVM::PushToNativePointerList(JSNativePointer *array)
418 {
419 nativePointerList_.emplace_back(array);
420 }
421
RemoveFromNativePointerList(JSNativePointer * array)422 void EcmaVM::RemoveFromNativePointerList(JSNativePointer *array)
423 {
424 auto iter = std::find(nativePointerList_.begin(), nativePointerList_.end(), array);
425 if (iter != nativePointerList_.end()) {
426 JSNativePointer *object = *iter;
427 object->Destroy();
428 nativePointerList_.erase(iter);
429 }
430 }
431
PushToDeregisterModuleList(CString module)432 void EcmaVM::PushToDeregisterModuleList(CString module)
433 {
434 deregisterModuleList_.emplace_back(module);
435 }
436
RemoveFromDeregisterModuleList(CString module)437 void EcmaVM::RemoveFromDeregisterModuleList(CString module)
438 {
439 auto iter = std::find(deregisterModuleList_.begin(), deregisterModuleList_.end(), module);
440 if (iter != deregisterModuleList_.end()) {
441 deregisterModuleList_.erase(iter);
442 }
443 }
444
ContainInDeregisterModuleList(CString module)445 bool EcmaVM::ContainInDeregisterModuleList(CString module)
446 {
447 return (std::find(deregisterModuleList_.begin(), deregisterModuleList_.end(), module)
448 != deregisterModuleList_.end());
449 }
450
ClearBufferData()451 void EcmaVM::ClearBufferData()
452 {
453 for (auto iter : nativePointerList_) {
454 iter->Destroy();
455 }
456 nativePointerList_.clear();
457 thread_->GetCurrentEcmaContext()->ClearBufferData();
458 internalNativeMethods_.clear();
459 workerList_.clear();
460 deregisterModuleList_.clear();
461 }
462
CollectGarbage(TriggerGCType gcType,GCReason reason) const463 void EcmaVM::CollectGarbage(TriggerGCType gcType, GCReason reason) const
464 {
465 heap_->CollectGarbage(gcType, reason);
466 }
467
Iterate(const RootVisitor & v,const RootRangeVisitor & rv)468 void EcmaVM::Iterate(const RootVisitor &v, const RootRangeVisitor &rv)
469 {
470 rv(Root::ROOT_VM, ObjectSlot(ToUintPtr(&internalNativeMethods_.front())),
471 ObjectSlot(ToUintPtr(&internalNativeMethods_.back()) + JSTaggedValue::TaggedTypeSize()));
472 if (!WIN_OR_MAC_OR_IOS_PLATFORM) {
473 snapshotEnv_->Iterate(v);
474 }
475 }
476
477 #if defined(ECMASCRIPT_SUPPORT_HEAPPROFILER)
DeleteHeapProfile()478 void EcmaVM::DeleteHeapProfile()
479 {
480 if (heapProfile_ == nullptr) {
481 return;
482 }
483 const_cast<NativeAreaAllocator *>(GetNativeAreaAllocator())->Delete(heapProfile_);
484 heapProfile_ = nullptr;
485 }
486
GetHeapProfile()487 HeapProfilerInterface *EcmaVM::GetHeapProfile()
488 {
489 if (heapProfile_ != nullptr) {
490 return heapProfile_;
491 }
492 return nullptr;
493 }
494
GetOrNewHeapProfile()495 HeapProfilerInterface *EcmaVM::GetOrNewHeapProfile()
496 {
497 if (heapProfile_ != nullptr) {
498 return heapProfile_;
499 }
500 heapProfile_ = const_cast<NativeAreaAllocator *>(GetNativeAreaAllocator())->New<HeapProfiler>(this);
501 ASSERT(heapProfile_ != nullptr);
502 return heapProfile_;
503 }
504
StartHeapTracking()505 void EcmaVM::StartHeapTracking()
506 {
507 heap_->StartHeapTracking();
508 }
509
StopHeapTracking()510 void EcmaVM::StopHeapTracking()
511 {
512 heap_->StopHeapTracking();
513 }
514 #endif
515
516 // NOLINTNEXTLINE(modernize-avoid-c-arrays)
517 void *EcmaVM::InternalMethodTable[] = {
518 reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsBoundFunction),
519 reinterpret_cast<void *>(builtins::BuiltinsGlobal::CallJsProxy),
520 reinterpret_cast<void *>(builtins::BuiltinsObject::CreateDataPropertyOnObjectFunctions),
521 #ifdef ARK_SUPPORT_INTL
522 reinterpret_cast<void *>(builtins::BuiltinsCollator::AnonymousCollator),
523 reinterpret_cast<void *>(builtins::BuiltinsDateTimeFormat::AnonymousDateTimeFormat),
524 reinterpret_cast<void *>(builtins::BuiltinsNumberFormat::NumberFormatInternalFormatNumber),
525 #endif
526 reinterpret_cast<void *>(builtins::BuiltinsProxy::InvalidateProxyFunction),
527 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitFulfilled),
528 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AsyncAwaitRejected),
529 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ResolveElementFunction),
530 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Resolve),
531 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Reject),
532 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::Executor),
533 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AnyRejectElementFunction),
534 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledResolveElementFunction),
535 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::AllSettledRejectElementFunction),
536 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::ThenFinally),
537 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::CatchFinally),
538 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::valueThunkFunction),
539 reinterpret_cast<void *>(builtins::BuiltinsPromiseHandler::throwerFunction),
540 reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorFulfilledFunc),
541 reinterpret_cast<void *>(JSAsyncGeneratorObject::ProcessorRejectedFunc),
542 reinterpret_cast<void *>(JSAsyncFromSyncIterator::AsyncFromSyncIterUnwarpFunction)
543 };
544
GenerateInternalNativeMethods()545 void EcmaVM::GenerateInternalNativeMethods()
546 {
547 size_t length = static_cast<size_t>(MethodIndex::METHOD_END);
548 constexpr uint32_t numArgs = 2; // function object and this
549 for (size_t i = 0; i < length; i++) {
550 auto method = factory_->NewMethod(nullptr, MemSpaceType::NON_MOVABLE);
551 method->SetNativePointer(InternalMethodTable[i]);
552 method->SetNativeBit(true);
553 method->SetNumArgsWithCallField(numArgs);
554 method->SetFunctionKind(FunctionKind::NORMAL_FUNCTION);
555 internalNativeMethods_.emplace_back(method.GetTaggedValue());
556 }
557 }
558
GetMethodByIndex(MethodIndex idx)559 JSTaggedValue EcmaVM::GetMethodByIndex(MethodIndex idx)
560 {
561 auto index = static_cast<uint8_t>(idx);
562 ASSERT(index < internalNativeMethods_.size());
563 return internalNativeMethods_[index];
564 }
565
TriggerConcurrentCallback(JSTaggedValue result,JSTaggedValue hint)566 void EcmaVM::TriggerConcurrentCallback(JSTaggedValue result, JSTaggedValue hint)
567 {
568 if (concurrentCallback_ == nullptr) {
569 LOG_ECMA(DEBUG) << "Only trigger concurrent callback in taskpool thread";
570 return;
571 }
572
573 bool success = true;
574 if (result.IsJSPromise()) {
575 // Async concurrent will return Promise
576 auto promise = JSPromise::Cast(result.GetTaggedObject());
577 auto status = promise->GetPromiseState();
578 if (status == PromiseState::PENDING) {
579 result = JSHandle<JSTaggedValue>::Cast(factory_->GetJSError(
580 ErrorType::ERROR, "Can't return Promise in pending state")).GetTaggedValue();
581 } else {
582 result = promise->GetPromiseResult();
583 }
584
585 if (status != PromiseState::FULFILLED) {
586 success = false;
587 }
588 }
589
590 JSHandle<JSTaggedValue> functionValue(thread_, hint);
591 if (!functionValue->IsJSFunction()) {
592 LOG_ECMA(ERROR) << "TriggerConcurrentCallback hint is not function";
593 return;
594 }
595 JSHandle<JSFunction> functionInfo(functionValue);
596 JSTaggedValue extraInfoValue = functionInfo->GetFunctionExtraInfo();
597 if (!extraInfoValue.IsJSNativePointer()) {
598 LOG_ECMA(INFO) << "FunctionExtraInfo is not JSNativePointer";
599 return;
600 }
601 JSHandle<JSNativePointer> extraInfo(thread_, extraInfoValue);
602 void *taskInfo = extraInfo->GetData();
603
604 concurrentCallback_(JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread_, result)), success,
605 taskInfo, concurrentData_);
606 }
607
DumpCallTimeInfo()608 void EcmaVM::DumpCallTimeInfo()
609 {
610 if (callTimer_ != nullptr) {
611 callTimer_->PrintAllStats();
612 }
613 }
614
WorkersetInfo(EcmaVM * hostVm,EcmaVM * workerVm)615 void EcmaVM::WorkersetInfo(EcmaVM *hostVm, EcmaVM *workerVm)
616 {
617 os::memory::LockHolder lock(mutex_);
618 auto thread = workerVm->GetJSThread();
619 if (thread != nullptr && hostVm != nullptr) {
620 auto tid = thread->GetThreadId();
621 if (tid != 0) {
622 workerList_.emplace(tid, workerVm);
623 }
624 }
625 }
626
GetWorkerVm(uint32_t tid)627 EcmaVM *EcmaVM::GetWorkerVm(uint32_t tid)
628 {
629 os::memory::LockHolder lock(mutex_);
630 EcmaVM *workerVm = nullptr;
631 if (!workerList_.empty()) {
632 auto iter = workerList_.find(tid);
633 if (iter != workerList_.end()) {
634 workerVm = iter->second;
635 }
636 }
637 return workerVm;
638 }
639
DeleteWorker(EcmaVM * hostVm,EcmaVM * workerVm)640 bool EcmaVM::DeleteWorker(EcmaVM *hostVm, EcmaVM *workerVm)
641 {
642 os::memory::LockHolder lock(mutex_);
643 auto thread = workerVm->GetJSThread();
644 if (hostVm != nullptr && thread != nullptr) {
645 auto tid = thread->GetThreadId();
646 if (tid == 0) {
647 return false;
648 }
649 auto iter = workerList_.find(tid);
650 if (iter != workerList_.end()) {
651 workerList_.erase(iter);
652 return true;
653 }
654 return false;
655 }
656 return false;
657 }
658
SuspendWorkerVm(uint32_t tid)659 bool EcmaVM::SuspendWorkerVm(uint32_t tid)
660 {
661 os::memory::LockHolder lock(mutex_);
662 if (!workerList_.empty()) {
663 auto iter = workerList_.find(tid);
664 if (iter != workerList_.end()) {
665 return DFXJSNApi::SuspendVM(iter->second);
666 }
667 }
668 return false;
669 }
670
ResumeWorkerVm(uint32_t tid)671 void EcmaVM::ResumeWorkerVm(uint32_t tid)
672 {
673 os::memory::LockHolder lock(mutex_);
674 if (!workerList_.empty()) {
675 auto iter = workerList_.find(tid);
676 if (iter != workerList_.end()) {
677 DFXJSNApi::ResumeVM(iter->second);
678 }
679 }
680 }
681 } // namespace panda::ecmascript
682