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