/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "jsnapi_helper.h" #include #include #include "ecmascript/base/builtins_base.h" #include "ecmascript/base/json_parser.h" #include "ecmascript/base/json_stringifier.h" #include "ecmascript/base/path_helper.h" #include "ecmascript/base/string_helper.h" #include "ecmascript/base/typed_array_helper-inl.h" #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h" #endif #include "ecmascript/debugger/js_debugger_manager.h" #include "ecmascript/ecma_global_storage.h" #include "ecmascript/ecma_runtime_call_info.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/aot_file_manager.h" #include "ecmascript/global_env.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/jobs/micro_job_queue.h" #include "ecmascript/jspandafile/debug_info_extractor.h" #include "ecmascript/jspandafile/js_pandafile_executor.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/jspandafile/quick_fix_manager.h" #include "ecmascript/js_array.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_bigint.h" #include "ecmascript/js_collator.h" #include "ecmascript/js_dataview.h" #include "ecmascript/byte_array.h" #include "ecmascript/js_date_time_format.h" #include "ecmascript/js_file_path.h" #include "ecmascript/js_function.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_iterator.h" #include "ecmascript/js_map.h" #include "ecmascript/js_map_iterator.h" #include "ecmascript/js_number_format.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_promise.h" #include "ecmascript/js_regexp.h" #include "ecmascript/js_runtime_options.h" #include "ecmascript/js_serializer.h" #include "ecmascript/js_set.h" #include "ecmascript/js_set_iterator.h" #include "ecmascript/js_tagged_number.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_typed_array.h" #include "ecmascript/linked_hash_table.h" #include "ecmascript/log.h" #include "ecmascript/mem/mem.h" #include "ecmascript/mem/mem_map_allocator.h" #include "ecmascript/mem/region.h" #include "ecmascript/module/js_module_manager.h" #include "ecmascript/module/js_module_source_text.h" #include "ecmascript/object_factory.h" #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/platform/file.h" #include "ecmascript/tagged_array.h" #include "ecmascript/regexp/regexp_parser.h" #include "ohos/init_data.h" #include "os/mutex.h" #if defined(PANDA_TARGET_IOS) namespace OHOS::ArkCompiler::Toolchain { using DebuggerPostTask = std::function &&)>; extern "C" { bool StartDebug(const std::string& componentName, void* vm, bool isDebugMode, int32_t instanceId, const DebuggerPostTask& debuggerPostTask); void StopDebug(const std::string& componentName); } } // namespace OHOS::ArkCompiler::Toolchain const std::string DEBUGGER_NAME = "PandaDebugger"; #endif namespace panda { using ecmascript::ECMAObject; using ecmascript::EcmaString; using ecmascript::EcmaStringAccessor; using ecmascript::ErrorType; using ecmascript::FastRuntimeStub; using ecmascript::GlobalEnv; using ecmascript::GlobalEnvConstants; using ecmascript::EcmaRuntimeCallInfo; using ecmascript::JSArray; using ecmascript::JSArrayBuffer; using ecmascript::JSDataView; using ecmascript::ByteArray; using ecmascript::JSDate; using ecmascript::JSFunction; using ecmascript::JSFunctionBase; using ecmascript::JSHClass; using ecmascript::JSMap; using ecmascript::Method; using ecmascript::JSNativePointer; using ecmascript::JSObject; using ecmascript::JSPandaFile; using ecmascript::JSPandaFileManager; using ecmascript::JSPrimitiveRef; using ecmascript::JSPromise; using ecmascript::JSRegExp; using ecmascript::JSSerializer; using ecmascript::JSSet; using ecmascript::JSSymbol; using ecmascript::JSTaggedNumber; using ecmascript::JSTaggedType; using ecmascript::JSTaggedValue; using ecmascript::JSThread; using ecmascript::LinkedHashMap; using ecmascript::LinkedHashSet; using ecmascript::ObjectFactory; using ecmascript::PromiseCapability; using ecmascript::PropertyDescriptor; using ecmascript::OperationResult; using ecmascript::Region; using ecmascript::TaggedArray; using ecmascript::JSTypedArray; using ecmascript::base::BuiltinsBase; using ecmascript::base::JsonParser; using ecmascript::base::JsonStringifier; using ecmascript::base::StringHelper; using ecmascript::base::TypedArrayHelper; using ecmascript::job::MicroJobQueue; using ecmascript::job::QueueType; using ecmascript::JSRuntimeOptions; using ecmascript::BigInt; using ecmascript::MemMapAllocator; using ecmascript::JSMapIterator; using ecmascript::JSSetIterator; using ecmascript::IterationKind; using ecmascript::JSGeneratorState; using ecmascript::JSIterator; using ecmascript::JSGeneratorFunction; using ecmascript::JSGeneratorObject; using ecmascript::GeneratorContext; using ecmascript::JSCollator; using ecmascript::JSDateTimeFormat; using ecmascript::JSNumberFormat; using ecmascript::RegExpParser; using ecmascript::DebugInfoExtractor; using ecmascript::base::NumberHelper; template using JSHandle = ecmascript::JSHandle; template using JSMutableHandle = ecmascript::JSMutableHandle; using PathHelper = ecmascript::base::PathHelper; namespace { // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) constexpr std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; } int JSNApi::vmCount_ = 0; bool JSNApi::initialize_ = false; static os::memory::Mutex mutex; // ------------------------------------ Panda ----------------------------------------------- EcmaVM *JSNApi::CreateJSVM(const RuntimeOption &option) { JSRuntimeOptions runtimeOptions; runtimeOptions.SetArkProperties(option.GetArkProperties()); runtimeOptions.SetArkBundleName(option.GetArkBundleName()); runtimeOptions.SetLongPauseTime(option.GetLongPauseTime()); runtimeOptions.SetGcThreadNum(option.GetGcThreadNum()); runtimeOptions.SetIsWorker(option.GetIsWorker()); // Mem runtimeOptions.SetHeapSizeLimit(option.GetGcPoolSize()); // Disable the asm-interpreter of ark-engine for ios-platform temporarily. #if !defined(PANDA_TARGET_IOS) && !defined(DISABLE_ASM_INTERPRETER) // asmInterpreter runtimeOptions.SetEnableAsmInterpreter(option.GetEnableAsmInterpreter()); #else runtimeOptions.SetEnableAsmInterpreter(false); #endif runtimeOptions.SetAsmOpcodeDisableRange(option.GetAsmOpcodeDisableRange()); // aot runtimeOptions.SetEnableAOT(option.GetEnableAOT()); runtimeOptions.SetEnablePGOProfiler(option.GetEnableProfile()); runtimeOptions.SetPGOProfilerPath(option.GetProfileDir()); // Dfx runtimeOptions.SetLogLevel(option.GetLogLevel()); runtimeOptions.SetEnableArkTools(option.GetEnableArkTools()); return CreateEcmaVM(runtimeOptions); } EcmaVM *JSNApi::CreateEcmaVM(const JSRuntimeOptions &options) { { os::memory::LockHolder lock(mutex); vmCount_++; if (!initialize_) { ecmascript::Log::Initialize(options); InitializeIcuData(options); InitializeMemMapAllocator(); InitializePGOProfiler(options); initialize_ = true; } } auto config = ecmascript::EcmaParamConfiguration(options.IsWorker(), MemMapAllocator::GetInstance()->GetCapacity()); LOG_ECMA(INFO) << " [NAPI]: CreateEcmaVM, isWorker = " << options.IsWorker() << ", vmCount = " << vmCount_; MemMapAllocator::GetInstance()->IncreaseAndCheckReserved(config.GetMaxHeapSize()); return EcmaVM::Create(options, config); } void JSNApi::DestroyJSVM(EcmaVM *ecmaVm) { os::memory::LockHolder lock(mutex); if (!initialize_) { return; } auto &config = ecmaVm->GetEcmaParamConfiguration(); MemMapAllocator::GetInstance()->DecreaseReserved(config.GetMaxHeapSize()); EcmaVM::Destroy(ecmaVm); vmCount_--; if (vmCount_ <= 0) { DestoryAnDataManager(); DestroyMemMapAllocator(); DestroyPGOProfiler(); initialize_ = false; } } void JSNApi::CleanJSVMCache() { JSPandaFileManager::GetInstance()->ClearCache(); } void JSNApi::TriggerGC(const EcmaVM *vm, TRIGGER_GC_TYPE gcType) { if (vm->GetJSThread() != nullptr && vm->IsInitialized()) { switch (gcType) { case TRIGGER_GC_TYPE::SEMI_GC: vm->CollectGarbage(ecmascript::TriggerGCType::YOUNG_GC); break; case TRIGGER_GC_TYPE::OLD_GC: vm->CollectGarbage(ecmascript::TriggerGCType::OLD_GC); break; case TRIGGER_GC_TYPE::FULL_GC: vm->CollectGarbage(ecmascript::TriggerGCType::FULL_GC); break; default: break; } } } void JSNApi::ThrowException(const EcmaVM *vm, Local error) { auto thread = vm->GetJSThread(); thread->SetException(JSNApiHelper::ToJSTaggedValue(*error)); } #if defined(ECMASCRIPT_SUPPORT_DEBUGGER) #if !defined(PANDA_TARGET_IOS) bool JSNApi::StartDebugger(const char *libraryPath, EcmaVM *vm, bool isDebugMode, int32_t instanceId, const DebuggerPostTask &debuggerPostTask) { const auto &handler = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); if (handler.IsValid()) { return false; } auto handle = panda::os::library_loader::Load(std::string(libraryPath)); if (!handle) { return false; } using StartDebugger = bool (*)(const std::string &, EcmaVM *, bool, int32_t, const DebuggerPostTask &); auto sym = panda::os::library_loader::ResolveSymbol(handle.Value(), "StartDebug"); if (!sym) { LOG_ECMA(ERROR) << sym.Error().ToString(); return false; } bool ret = reinterpret_cast(sym.Value())("PandaDebugger", vm, isDebugMode, instanceId, debuggerPostTask); if (ret) { vm->GetJsDebuggerManager()->SetDebugMode(isDebugMode); vm->GetJsDebuggerManager()->SetDebugLibraryHandle(std::move(handle.Value())); } return ret; } bool JSNApi::StopDebugger(EcmaVM *vm) { if (vm == nullptr) { return false; } const auto &handle = vm->GetJsDebuggerManager()->GetDebugLibraryHandle(); using StopDebug = void (*)(const std::string &); auto sym = panda::os::library_loader::ResolveSymbol(handle, "StopDebug"); if (!sym) { LOG_ECMA(ERROR) << sym.Error().ToString(); return false; } reinterpret_cast(sym.Value())("PandaDebugger"); vm->GetJsDebuggerManager()->SetDebugMode(false); return true; } #else bool JSNApi::StartDebugger(EcmaVM *vm, bool isDebugMode, int32_t instanceId, const DebuggerPostTask &debuggerPostTask) { bool ret = OHOS::ArkCompiler::Toolchain::StartDebug(DEBUGGER_NAME, vm, isDebugMode, instanceId, debuggerPostTask); if (ret) { vm->GetJsDebuggerManager()->SetDebugMode(isDebugMode); } return ret; } bool JSNApi::StopDebugger(EcmaVM *vm) { if (vm == nullptr) { return false; } OHOS::ArkCompiler::Toolchain::StopDebug(DEBUGGER_NAME); vm->GetJsDebuggerManager()->SetDebugMode(false); return true; } #endif bool JSNApi::IsMixedDebugEnabled(const EcmaVM *vm) { return vm->GetJsDebuggerManager()->IsMixedDebugEnabled(); } void JSNApi::NotifyNativeCalling(const EcmaVM *vm, const void *nativeAddress) { vm->GetJsDebuggerManager()->GetNotificationManager()->NativeCallingEvent(nativeAddress); } #endif void JSNApi::LoadAotFile(EcmaVM *vm, const std::string &hapPath) { if (!ecmascript::AnFileDataManager::GetInstance()->IsEnable()) { return; } std::string aotFileName = ecmascript::AnFileDataManager::GetInstance()->GetDir(); aotFileName += ecmascript::JSFilePath::GetFileName(hapPath); LOG_ECMA(INFO) << "start to load aot file: " << aotFileName; vm->LoadAOTFiles(aotFileName); } bool JSNApi::Execute(EcmaVM *vm, const std::string &fileName, const std::string &entry, bool needUpdate) { LOG_ECMA(DEBUG) << "start to execute ark file: " << fileName; JSThread *thread = vm->GetAssociatedJSThread(); if (!ecmascript::JSPandaFileExecutor::ExecuteFromFile(thread, fileName.c_str(), entry, needUpdate)) { LOG_ECMA(ERROR) << "Cannot execute ark file '" << fileName << "' with entry '" << entry << "'" << std::endl; return false; } return true; } bool JSNApi::Execute(EcmaVM *vm, const uint8_t *data, int32_t size, const std::string &entry, const std::string &filename, bool needUpdate) { LOG_ECMA(DEBUG) << "start to execute ark buffer: " << filename; JSThread *thread = vm->GetAssociatedJSThread(); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer( thread, data, size, entry, filename.c_str(), needUpdate)) { LOG_ECMA(ERROR) << "Cannot execute ark buffer file '" << filename << "' with entry '" << entry << "'" << std::endl; return false; } return true; } bool JSNApi::ExecuteModuleBuffer(EcmaVM *vm, const uint8_t *data, int32_t size, const std::string &filename, bool needUpdate) { LOG_ECMA(DEBUG) << "start to execute module buffer: " << filename; JSThread *thread = vm->GetAssociatedJSThread(); if (!ecmascript::JSPandaFileExecutor::ExecuteModuleBuffer(thread, data, size, filename.c_str(), needUpdate)) { LOG_ECMA(ERROR) << "Cannot execute module buffer file '" << filename; return false; } return true; } void JSNApi::PreFork(EcmaVM *vm) { vm->PreFork(); } void JSNApi::PostFork(EcmaVM *vm, const RuntimeOption &option) { JSRuntimeOptions &jsOption = vm->GetJSOptions(); LOG_ECMA(INFO) << "asmint: " << jsOption.GetEnableAsmInterpreter() << ", aot: " << jsOption.GetEnableAOT() << ", bundle name: " << option.GetBundleName(); jsOption.SetEnablePGOProfiler(option.GetEnableProfile()); vm->ResetPGOProfiler(); if (jsOption.GetEnableAOT() && option.GetAnDir().size()) { ecmascript::AnFileDataManager::GetInstance()->SetDir(option.GetAnDir()); ecmascript::AnFileDataManager::GetInstance()->SetEnable(true); } vm->PostFork(); } void JSNApi::addWorker(EcmaVM *hostVm, EcmaVM *workerVm) { if (hostVm != nullptr && workerVm != nullptr) { hostVm->WorkersetInfo(hostVm, workerVm); } } bool JSNApi::DeleteWorker(EcmaVM *hostVm, EcmaVM *workerVm) { if (hostVm != nullptr && workerVm != nullptr) { return hostVm->DeleteWorker(hostVm, workerVm); } return false; } Local JSNApi::GetUncaughtException(const EcmaVM *vm) { return JSNApiHelper::ToLocal(vm->GetEcmaUncaughtException()); } Local JSNApi::GetAndClearUncaughtException(const EcmaVM *vm) { return JSNApiHelper::ToLocal(vm->GetAndClearEcmaUncaughtException()); } bool JSNApi::HasPendingException(const EcmaVM *vm) { return vm->GetJSThread()->HasPendingException(); } void JSNApi::EnableUserUncaughtErrorHandler(EcmaVM *vm) { return vm->EnableUserUncaughtErrorHandler(); } Local JSNApi::GetGlobalObject(const EcmaVM *vm) { JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle global(vm->GetJSThread(), globalEnv->GetGlobalObject()); return JSNApiHelper::ToLocal(global); } void JSNApi::ExecutePendingJob(const EcmaVM *vm) { EcmaVM::ConstCast(vm)->ExecutePromisePendingJob(); } uintptr_t JSNApi::GetHandleAddr(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } JSTaggedType value = *(reinterpret_cast(localAddress)); return ecmascript::EcmaHandleScope::NewHandle(vm->GetJSThread(), value); } uintptr_t JSNApi::GetGlobalHandleAddr(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } JSTaggedType value = *(reinterpret_cast(localAddress)); return vm->GetJSThread()->NewGlobalHandle(value); } uintptr_t JSNApi::SetWeak(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } return vm->GetJSThread()->SetWeak(localAddress); } uintptr_t JSNApi::SetWeakCallback(const EcmaVM *vm, uintptr_t localAddress, void *ref, WeakRefClearCallBack firstCallback, WeakRefClearCallBack secondCallback) { if (localAddress == 0) { return 0; } return vm->GetJSThread()->SetWeak(localAddress, ref, firstCallback, secondCallback); } uintptr_t JSNApi::ClearWeak(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return 0; } if (JSTaggedValue(reinterpret_cast(localAddress)->GetObject()) .IsUndefined()) { LOG_ECMA(ERROR) << "The object of weak reference has been recycled!"; return 0; } return vm->GetJSThread()->ClearWeak(localAddress); } bool JSNApi::IsWeak(const EcmaVM *vm, uintptr_t localAddress) { if (localAddress == 0) { return false; } return vm->GetJSThread()->IsWeak(localAddress); } void JSNApi::DisposeGlobalHandleAddr(const EcmaVM *vm, uintptr_t addr) { if (addr == 0 || !reinterpret_cast(addr)->IsUsing()) { return; } vm->GetJSThread()->DisposeGlobalHandle(addr); } void *JSNApi::SerializeValue(const EcmaVM *vm, Local value, Local transfer) { ecmascript::JSThread *thread = vm->GetJSThread(); ecmascript::Serializer serializer(thread); JSHandle arkValue = JSNApiHelper::ToJSHandle(value); JSHandle arkTransfer = JSNApiHelper::ToJSHandle(transfer); std::unique_ptr data; if (serializer.WriteValue(thread, arkValue, arkTransfer)) { data = serializer.Release(); } if (data == nullptr) { return nullptr; } else { return reinterpret_cast(data.release()); } } Local JSNApi::DeserializeValue(const EcmaVM *vm, void *recoder, void *hint) { ecmascript::JSThread *thread = vm->GetJSThread(); std::unique_ptr data(reinterpret_cast(recoder)); ecmascript::Deserializer deserializer(thread, data.release(), hint); JSHandle result = deserializer.ReadValue(); return JSNApiHelper::ToLocal(result); } void JSNApi::DeleteSerializationData(void *data) { ecmascript::SerializationData *value = reinterpret_cast(data); delete value; value = nullptr; } void HostPromiseRejectionTracker(const EcmaVM *vm, const JSHandle promise, const JSHandle reason, const ecmascript::PromiseRejectionEvent operation, void* data) { ecmascript::PromiseRejectCallback promiseRejectCallback = vm->GetPromiseRejectCallback(); if (promiseRejectCallback != nullptr) { Local promiseVal = JSNApiHelper::ToLocal(JSHandle::Cast(promise)); PromiseRejectInfo promiseRejectInfo(promiseVal, JSNApiHelper::ToLocal(reason), static_cast(operation), data); promiseRejectCallback(reinterpret_cast(&promiseRejectInfo)); } } void JSNApi::SetHostPromiseRejectionTracker(EcmaVM *vm, void *cb, void* data) { vm->SetHostPromiseRejectionTracker(HostPromiseRejectionTracker); vm->SetPromiseRejectCallback(reinterpret_cast(cb)); vm->SetData(data); } void JSNApi::SetHostResolveBufferTracker(EcmaVM *vm, std::function(std::string dirPath, std::string requestPath)> cb) { vm->SetResolveBufferCallback(cb); } void JSNApi::SetNativePtrGetter(EcmaVM *vm, void* cb) { vm->SetNativePtrGetter(reinterpret_cast(cb)); } void JSNApi::SetHostEnqueueJob(const EcmaVM *vm, Local cb) { JSHandle fun = JSHandle::Cast(JSNApiHelper::ToJSHandle(cb)); JSHandle array = vm->GetFactory()->EmptyArray(); JSHandle job = vm->GetMicroJobQueue(); MicroJobQueue::EnqueueJob(vm->GetJSThread(), job, QueueType::QUEUE_PROMISE, fun, array); } PromiseRejectInfo::PromiseRejectInfo(Local promise, Local reason, PromiseRejectInfo::PROMISE_REJECTION_EVENT operation, void* data) : promise_(promise), reason_(reason), operation_(operation), data_(data) {} Local PromiseRejectInfo::GetPromise() const { return promise_; } Local PromiseRejectInfo::GetReason() const { return reason_; } PromiseRejectInfo::PROMISE_REJECTION_EVENT PromiseRejectInfo::GetOperation() const { return operation_; } void* PromiseRejectInfo::GetData() const { return data_; } bool JSNApi::ExecuteModuleFromBuffer(EcmaVM *vm, const void *data, int32_t size, const std::string &file) { JSThread *thread = vm->GetAssociatedJSThread(); if (!ecmascript::JSPandaFileExecutor::ExecuteFromBuffer(thread, data, size, ENTRY_POINTER, file.c_str())) { std::cerr << "Cannot execute panda file from memory" << std::endl; return false; } return true; } Local JSNApi::GetExportObject(EcmaVM *vm, const std::string &file, const std::string &key) { ecmascript::CString entry = file.c_str(); JSThread *thread = vm->GetJSThread(); ecmascript::CString name = vm->GetAssetPath(); if (!vm->IsBundlePack()) { entry = PathHelper::ParseOhmUrl(vm, entry, name); const JSPandaFile *jsPandaFile = JSPandaFileManager::GetInstance()->LoadJSPandaFile(thread, name, entry.c_str(), false); if (jsPandaFile == nullptr) { JSHandle exportObj(thread, JSTaggedValue::Null()); return JSNApiHelper::ToLocal(exportObj); } if (!jsPandaFile->IsRecordWithBundleName()) { PathHelper::CroppingRecord(entry); } } ecmascript::ModuleManager *moduleManager = vm->GetModuleManager(); JSHandle ecmaModule = moduleManager->HostGetImportedModule(entry); if (ecmaModule->GetIsNewBcVersion()) { int index = ecmascript::ModuleManager::GetExportObjectIndex(vm, ecmaModule, key); JSTaggedValue result = ecmaModule->GetModuleValue(thread, index, false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } ObjectFactory *factory = vm->GetFactory(); JSHandle keyHandle = factory->NewFromASCII(key.c_str()); JSTaggedValue result = ecmaModule->GetModuleValue(thread, keyHandle.GetTaggedValue(), false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } Local JSNApi::GetExportObjectFromBuffer(EcmaVM *vm, const std::string &file, const std::string &key) { ecmascript::ModuleManager *moduleManager = vm->GetModuleManager(); JSThread *thread = vm->GetJSThread(); JSHandle ecmaModule = moduleManager->HostGetImportedModule(file.c_str()); if (ecmaModule->GetIsNewBcVersion()) { int index = ecmascript::ModuleManager::GetExportObjectIndex(vm, ecmaModule, key); JSTaggedValue result = ecmaModule->GetModuleValue(thread, index, false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } ObjectFactory *factory = vm->GetFactory(); JSHandle keyHandle = factory->NewFromASCII(key.c_str()); JSTaggedValue result = ecmaModule->GetModuleValue(thread, keyHandle.GetTaggedValue(), false); JSHandle exportObj(thread, result); return JSNApiHelper::ToLocal(exportObj); } // Initialize IcuData Path void JSNApi::InitializeIcuData(const JSRuntimeOptions &options) { std::string icuPath = options.GetIcuDataPath(); if (icuPath == "default") { #if !WIN_OR_MAC_OR_IOS_PLATFORM && !defined(PANDA_TARGET_LINUX) SetHwIcuDirectory(); #endif } else { std::string absPath; if (ecmascript::RealPath(icuPath, absPath)) { u_setDataDirectory(absPath.c_str()); } } } void JSNApi::InitializeMemMapAllocator() { MemMapAllocator::GetInstance()->Initialize(ecmascript::DEFAULT_REGION_SIZE); } void JSNApi::DestroyMemMapAllocator() { MemMapAllocator::GetInstance()->Finalize(); } void JSNApi::InitializePGOProfiler(const ecmascript::JSRuntimeOptions &options) { ecmascript::PGOProfilerManager::GetInstance()->Initialize( options.GetPGOProfilerPath(), options.GetPGOHotnessThreshold()); } void JSNApi::DestroyPGOProfiler() { ecmascript::PGOProfilerManager::GetInstance()->Destroy(); } void JSNApi::DestoryAnDataManager() { ecmascript::AnFileDataManager::GetInstance()->SafeDestoryAllData(); } // ----------------------------------- HandleScope ------------------------------------- LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) { auto thread = reinterpret_cast(thread_); prevNext_ = thread->GetHandleScopeStorageNext(); prevEnd_ = thread->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = thread->GetCurrentHandleStorageIndex(); thread->HandleScopeCountAdd(); } LocalScope::LocalScope(const EcmaVM *vm, JSTaggedType value) : thread_(vm->GetJSThread()) { auto thread = reinterpret_cast(thread_); ecmascript::EcmaHandleScope::NewHandle(thread, value); prevNext_ = thread->GetHandleScopeStorageNext(); prevEnd_ = thread->GetHandleScopeStorageEnd(); prevHandleStorageIndex_ = thread->GetCurrentHandleStorageIndex(); thread->HandleScopeCountAdd(); } LocalScope::~LocalScope() { auto thread = reinterpret_cast(thread_); thread->HandleScopeCountDec(); thread->SetHandleScopeStorageNext(static_cast(prevNext_)); if (thread->GetHandleScopeStorageEnd() != prevEnd_) { thread->SetHandleScopeStorageEnd(static_cast(prevEnd_)); thread->ShrinkHandleStorage(prevHandleStorageIndex_); } } // ----------------------------------- EscapeLocalScope ------------------------------ EscapeLocalScope::EscapeLocalScope(const EcmaVM *vm) : LocalScope(vm, JSTaggedValue::Undefined().GetRawData()) { auto thread = vm->GetJSThread(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) escapeHandle_ = ToUintPtr(thread->GetHandleScopeStorageNext() - 1); } // ----------------------------------- PritimitiveRef --------------------------------------- Local PrimitiveRef::GetValue(const EcmaVM *vm) { JSHandle obj = JSNApiHelper::ToJSHandle(this); if (obj->IsJSPrimitiveRef()) { JSTaggedValue primitiveValue = JSPrimitiveRef::Cast(obj->GetTaggedObject())->GetValue(); JSHandle value = JSHandle(vm->GetJSThread(), primitiveValue); return JSNApiHelper::ToLocal(value); } return Local(); } // ----------------------------------- NumberRef --------------------------------------- Local NumberRef::New(const EcmaVM *vm, double input) { JSThread *thread = vm->GetJSThread(); if (std::isnan(input)) { input = ecmascript::base::NAN_VALUE; } JSHandle number(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(number); } Local NumberRef::New(const EcmaVM *vm, int32_t input) { JSThread *thread = vm->GetJSThread(); JSHandle number(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(number); } Local NumberRef::New(const EcmaVM *vm, uint32_t input) { JSThread *thread = vm->GetJSThread(); JSHandle number(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(number); } Local NumberRef::New(const EcmaVM *vm, int64_t input) { JSThread *thread = vm->GetJSThread(); JSHandle number(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(number); } double NumberRef::Value() { return JSTaggedNumber(JSNApiHelper::ToJSTaggedValue(this)).GetNumber(); } // ----------------------------------- BigIntRef --------------------------------------- Local BigIntRef::New(const EcmaVM *vm, uint64_t input) { JSThread *thread = vm->GetJSThread(); JSHandle big = BigInt::Uint64ToBigInt(thread, input); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); } Local BigIntRef::New(const EcmaVM *vm, int64_t input) { JSThread *thread = vm->GetJSThread(); JSHandle big = BigInt::Int64ToBigInt(thread, input); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); } Local BigIntRef::CreateBigWords(const EcmaVM *vm, bool sign, uint32_t size, const uint64_t* words) { JSThread *thread = vm->GetJSThread(); JSHandle big = BigInt::CreateBigWords(thread, sign, size, words); JSHandle bigint = JSHandle::Cast(big); return JSNApiHelper::ToLocal(bigint); } void BigIntRef::BigIntToInt64(const EcmaVM *vm, int64_t *cValue, bool *lossless) { JSThread *thread = vm->GetJSThread(); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); BigInt::BigIntToInt64(thread, bigintVal, cValue, lossless); } void BigIntRef::BigIntToUint64(const EcmaVM *vm, uint64_t *cValue, bool *lossless) { JSThread *thread = vm->GetJSThread(); JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); BigInt::BigIntToUint64(thread, bigintVal, cValue, lossless); } void BigIntRef::GetWordsArray(bool* signBit, size_t wordCount, uint64_t* words) { JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); uint32_t len = bigintVal->GetLength(); uint32_t count = 0; uint32_t index = 0; for (; index < wordCount - 1; ++index) { words[index] = static_cast(bigintVal->GetDigit(count++)); words[index] |= static_cast(bigintVal->GetDigit(count++)) << 32; // 32 : int32_t bits } if (len % 2 == 0) { // 2 : len is odd or even words[index] = static_cast(bigintVal->GetDigit(count++)); words[index] |= static_cast(bigintVal->GetDigit(count++)) << 32; // 32 : int32_t bits } else { words[index] = static_cast(bigintVal->GetDigit(count++)); } *signBit = bigintVal->GetSign(); } uint32_t BigIntRef::GetWordsArraySize() { JSHandle bigintVal(JSNApiHelper::ToJSHandle(this)); uint32_t len = bigintVal->GetLength(); return len % 2 != 0 ? len / 2 + 1 : len / 2; // 2 : len is odd or even } // ----------------------------------- BooleanRef --------------------------------------- Local BooleanRef::New(const EcmaVM *vm, bool input) { JSThread *thread = vm->GetJSThread(); JSHandle boolean(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(boolean); } bool BooleanRef::Value() { return JSNApiHelper::ToJSTaggedValue(this).IsTrue(); } // ----------------------------------- IntegerRef --------------------------------------- Local IntegerRef::New(const EcmaVM *vm, int input) { JSThread *thread = vm->GetJSThread(); JSHandle integer(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(integer); } Local IntegerRef::NewFromUnsigned(const EcmaVM *vm, unsigned int input) { JSThread *thread = vm->GetJSThread(); JSHandle integer(thread, JSTaggedValue(input)); return JSNApiHelper::ToLocal(integer); } int IntegerRef::Value() { return JSNApiHelper::ToJSTaggedValue(this).GetInt(); } // ----------------------------------- StringRef ---------------------------------------- Local StringRef::NewFromUtf8(const EcmaVM *vm, const char *utf8, int length) { ObjectFactory *factory = vm->GetFactory(); if (length < 0) { JSHandle current(factory->NewFromUtf8(utf8)); return JSNApiHelper::ToLocal(current); } JSHandle current(factory->NewFromUtf8(reinterpret_cast(utf8), length)); return JSNApiHelper::ToLocal(current); } std::string StringRef::ToString() { return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).ToStdString(); } int32_t StringRef::Length() { return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).GetLength(); } int32_t StringRef::Utf8Length() { return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)).GetUtf8Length(); } int StringRef::WriteUtf8(char *buffer, int length) { return EcmaStringAccessor(JSNApiHelper::ToJSTaggedValue(this)) .WriteToFlatUtf8(reinterpret_cast(buffer), length); } Local StringRef::GetNapiWrapperString(const EcmaVM *vm) { JSHandle napiWapperString = vm->GetJSThread()->GlobalConstants()->GetHandledNapiWrapperString(); return JSNApiHelper::ToLocal(napiWapperString); } // ----------------------------------- SymbolRef ----------------------------------------- Local SymbolRef::New(const EcmaVM *vm, Local description) { ObjectFactory *factory = vm->GetFactory(); JSHandle symbol = factory->NewJSSymbol(); JSTaggedValue desc = JSNApiHelper::ToJSTaggedValue(*description); symbol->SetDescription(vm->GetJSThread(), desc); return JSNApiHelper::ToLocal(JSHandle(symbol)); } Local SymbolRef::GetDescription(const EcmaVM *vm) { JSTaggedValue description = JSSymbol::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetDescription(); if (!description.IsString()) { auto constants = vm->GetJSThread()->GlobalConstants(); return JSNApiHelper::ToLocal(constants->GetHandledEmptyString()); } JSHandle descriptionHandle(vm->GetJSThread(), description); return JSNApiHelper::ToLocal(descriptionHandle); } // -------------------------------- NativePointerRef ------------------------------------ Local NativePointerRef::New(const EcmaVM *vm, void *nativePointer, size_t nativeBindingsize) { ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer, nullptr, nullptr, false, nativeBindingsize); return JSNApiHelper::ToLocal(JSHandle(obj)); } Local NativePointerRef::New( const EcmaVM *vm, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize) { ObjectFactory *factory = vm->GetFactory(); JSHandle obj = factory->NewJSNativePointer(nativePointer, callBack, data, false, nativeBindingsize); return JSNApiHelper::ToLocal(JSHandle(obj)); } void *NativePointerRef::Value() { JSHandle nativePointer = JSNApiHelper::ToJSHandle(this); return JSHandle(nativePointer)->GetExternalPointer(); } // ----------------------------------- ObjectRef ---------------------------------------- Local ObjectRef::New(const EcmaVM *vm) { ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetObjectFunction()); JSHandle object(factory->NewJSObjectByConstructor(constructor)); return JSNApiHelper::ToLocal(object); } Local ObjectRef::New(const EcmaVM *vm, void *detach, void *attach) { ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle constructor(env->GetObjectFunction()); JSHandle object(factory->NewJSObjectByConstructor(constructor)); JSHandle detachKey = env->GetDetachSymbol(); JSHandle attachKey = env->GetAttachSymbol(); JSHandle detachValue = JSNApiHelper::ToJSHandle(NativePointerRef::New(vm, detach)); JSHandle attachValue = JSNApiHelper::ToJSHandle(NativePointerRef::New(vm, attach)); JSTaggedValue::SetProperty(vm->GetJSThread(), object, detachKey, detachValue); JSTaggedValue::SetProperty(vm->GetJSThread(), object, attachKey, attachValue); RETURN_VALUE_IF_ABRUPT(vm->GetJSThread(), JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(object); } bool ObjectRef::Set(const EcmaVM *vm, void *detach, void *attach) { [[maybe_unused]] LocalScope scope(vm); JSHandle env = vm->GetGlobalEnv(); JSHandle object = JSNApiHelper::ToJSHandle(this); JSHandle detachKey = env->GetDetachSymbol(); JSHandle attachKey = env->GetAttachSymbol(); JSHandle detachValue = JSNApiHelper::ToJSHandle(NativePointerRef::New(vm, detach)); JSHandle attachValue = JSNApiHelper::ToJSHandle(NativePointerRef::New(vm, attach)); bool detachResult = JSTaggedValue::SetProperty(vm->GetJSThread(), object, detachKey, detachValue); bool attachResult = JSTaggedValue::SetProperty(vm->GetJSThread(), object, attachKey, attachValue); RETURN_VALUE_IF_ABRUPT(vm->GetJSThread(), false); return detachResult && attachResult; } bool ObjectRef::Set(const EcmaVM *vm, Local key, Local value) { [[maybe_unused]] LocalScope scope(vm); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); JSHandle valueValue = JSNApiHelper::ToJSHandle(value); bool result = JSTaggedValue::SetProperty(vm->GetJSThread(), obj, keyValue, valueValue); RETURN_VALUE_IF_ABRUPT(vm->GetJSThread(), false); return result; } bool ObjectRef::Set(const EcmaVM *vm, uint32_t key, Local value) { [[maybe_unused]] LocalScope scope(vm); Local keyValue = NumberRef::New(vm, key); return Set(vm, keyValue, value); } bool ObjectRef::SetAccessorProperty(const EcmaVM *vm, Local key, Local getter, Local setter, PropertyAttribute attribute) { [[maybe_unused]] LocalScope scope(vm); JSThread *thread = vm->GetJSThread(); JSHandle getterValue = JSNApiHelper::ToJSHandle(getter); JSHandle setterValue = JSNApiHelper::ToJSHandle(setter); PropertyDescriptor desc(thread, attribute.IsWritable(), attribute.IsEnumerable(), attribute.IsConfigurable()); desc.SetValue(JSNApiHelper::ToJSHandle(attribute.GetValue(vm))); desc.SetSetter(setterValue); desc.SetGetter(getterValue); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); bool result = JSTaggedValue::DefineOwnProperty(thread, obj, keyValue, desc); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } Local ObjectRef::Get(const EcmaVM *vm, Local key) { EscapeLocalScope scope(vm); JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); if (!ret.GetPropertyMetaData().IsFound()) { return JSValueRef::Undefined(vm); } return scope.Escape(JSNApiHelper::ToLocal(ret.GetValue())); } Local ObjectRef::Get(const EcmaVM *vm, int32_t key) { Local keyValue = IntegerRef::New(vm, key); return Get(vm, keyValue); } bool ObjectRef::GetOwnProperty(const EcmaVM *vm, Local key, PropertyAttribute &property) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle keyValue = JSNApiHelper::ToJSHandle(key); PropertyDescriptor desc(thread); bool ret = JSObject::GetOwnProperty(thread, JSHandle(obj), keyValue, desc); if (!ret) { return false; } property.SetValue(JSNApiHelper::ToLocal(desc.GetValue())); if (desc.HasGetter()) { property.SetGetter(JSNApiHelper::ToLocal(desc.GetGetter())); } if (desc.HasSetter()) { property.SetSetter(JSNApiHelper::ToLocal(desc.GetSetter())); } if (desc.HasWritable()) { property.SetWritable(desc.IsWritable()); } if (desc.HasEnumerable()) { property.SetEnumerable(desc.IsEnumerable()); } if (desc.HasConfigurable()) { property.SetConfigurable(desc.IsConfigurable()); } return true; } Local ObjectRef::GetOwnPropertyNames(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj(JSNApiHelper::ToJSHandle(this)); JSHandle array(JSTaggedValue::GetOwnPropertyKeys(thread, obj)); JSHandle jsArray(JSArray::CreateArrayFromList(thread, array)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(jsArray); } Local ObjectRef::GetOwnEnumerablePropertyNames(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj(JSNApiHelper::ToJSHandle(this)); JSHandle array(JSObject::EnumerableOwnNames(thread, obj)); JSHandle jsArray(JSArray::CreateArrayFromList(thread, array)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(jsArray); } Local ObjectRef::GetPrototype(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle prototype(thread, JSTaggedValue::GetPrototype(thread, JSHandle(object))); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(prototype); } bool ObjectRef::DefineProperty(const EcmaVM *vm, Local key, PropertyAttribute attribute) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); PropertyDescriptor desc(thread, attribute.IsWritable(), attribute.IsEnumerable(), attribute.IsConfigurable()); desc.SetValue(JSNApiHelper::ToJSHandle(attribute.GetValue(vm))); bool result = object->DefinePropertyOrThrow(thread, object, keyValue, desc); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool ObjectRef::Has(const EcmaVM *vm, Local key) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); bool result = object->HasProperty(thread, object, keyValue); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool ObjectRef::Has(const EcmaVM *vm, uint32_t key) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); bool result = object->HasProperty(thread, object, key); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool ObjectRef::Delete(const EcmaVM *vm, Local key) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle keyValue(JSNApiHelper::ToJSHandle(key)); bool result = object->DeleteProperty(thread, object, keyValue); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool ObjectRef::Delete(const EcmaVM *vm, uint32_t key) { JSThread *thread = vm->GetJSThread(); JSHandle object(JSNApiHelper::ToJSHandle(this)); JSHandle keyHandle(thread, JSTaggedValue(key)); bool result = object->DeleteProperty(thread, object, keyHandle); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } void ObjectRef::SetNativePointerFieldCount(int32_t count) { JSHandle object(JSNApiHelper::ToJSHandle(this)); object->SetNativePointerFieldCount(count); } int32_t ObjectRef::GetNativePointerFieldCount() { JSHandle object(JSNApiHelper::ToJSHandle(this)); return object->GetNativePointerFieldCount(); } void *ObjectRef::GetNativePointerField(int32_t index) { JSHandle object(JSNApiHelper::ToJSHandle(this)); return object->GetNativePointerField(index); } void ObjectRef::SetNativePointerField(int32_t index, void *nativePointer, NativePointerCallback callBack, void *data, size_t nativeBindingsize) { JSHandle object(JSNApiHelper::ToJSHandle(this)); object->SetNativePointerField(index, nativePointer, callBack, data, nativeBindingsize); } // ----------------------------------- FunctionRef -------------------------------------- Local FunctionRef::New(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle current(factory->NewJSFunction(env, reinterpret_cast(Callback::RegisterCallback))); current->SetFunctionExtraInfo(thread, reinterpret_cast(nativeFunc), deleter, data, nativeBindingsize); current->SetCallNapi(callNapi); return JSNApiHelper::ToLocal(JSHandle(current)); } Local FunctionRef::NewClassFunction(EcmaVM *vm, FunctionCallback nativeFunc, Deleter deleter, void *data, bool callNapi, size_t nativeBindingsize) { EscapeLocalScope scope(vm); JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle env = vm->GetGlobalEnv(); JSHandle hclass = JSHandle::Cast(env->GetFunctionClassWithoutName()); JSHandle current = factory->NewJSFunctionByHClass(reinterpret_cast(Callback::RegisterCallback), hclass, ecmascript::FunctionKind::CLASS_CONSTRUCTOR); auto globalConst = thread->GlobalConstants(); JSHandle accessor = globalConst->GetHandledFunctionPrototypeAccessor(); current->SetPropertyInlinedProps(thread, JSFunction::CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); current->SetFunctionExtraInfo(thread, reinterpret_cast(nativeFunc), deleter, data, nativeBindingsize); JSHandle clsPrototype = JSFunction::NewJSFunctionPrototype(thread, factory, current); clsPrototype.GetTaggedValue().GetTaggedObject()->GetClass()->SetClassPrototype(true); JSHandle::Cast(current)->GetTaggedObject()->GetClass()->SetClassConstructor(true); current->SetClassConstructor(true); JSHandle parent = env->GetFunctionPrototype(); JSObject::SetPrototype(thread, JSHandle::Cast(current), parent); current->SetHomeObject(thread, clsPrototype); current->SetCallNapi(callNapi); Local result = JSNApiHelper::ToLocal(JSHandle(current)); return scope.Escape(result); } Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { EscapeLocalScope scope(vm); JSThread *thread = vm->GetJSThread(); if (!IsFunction()) { return JSValueRef::Undefined(vm); } vm->GetJsDebuggerManager()->ClearSingleStepper(); JSHandle func = JSNApiHelper::ToJSHandle(this); JSHandle thisValue = JSNApiHelper::ToJSHandle(thisObj); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, thisValue, undefined, length); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); for (int32_t i = 0; i < length; i++) { JSHandle arg = JSNApiHelper::ToJSHandle(argv[i]); info->SetCallArg(i, arg.GetTaggedValue()); } JSTaggedValue result = JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle resultValue(thread, result); EcmaVM::ConstCast(vm)->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); vm->GetHeap()->ClearKeptObjects(); return scope.Escape(JSNApiHelper::ToLocal(resultValue)); } Local FunctionRef::Constructor(const EcmaVM *vm, const Local argv[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t length) { JSThread *thread = vm->GetJSThread(); if (!IsFunction()) { return JSValueRef::Undefined(vm); } JSHandle func = JSNApiHelper::ToJSHandle(this); JSHandle newTarget = func; JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, undefined, newTarget, length); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); for (int32_t i = 0; i < length; i++) { JSHandle arg = JSNApiHelper::ToJSHandle(argv[i]); info->SetCallArg(i, arg.GetTaggedValue()); } JSTaggedValue result = JSFunction::Construct(info); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); JSHandle resultValue(thread, result); return JSNApiHelper::ToLocal(resultValue); } Local FunctionRef::GetFunctionPrototype(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle func = JSNApiHelper::ToJSHandle(this); JSHandle prototype(thread, JSHandle(func)->GetFunctionPrototype()); return JSNApiHelper::ToLocal(prototype); } bool FunctionRef::Inherit(const EcmaVM *vm, Local parent) { [[maybe_unused]] LocalScope scope(vm); JSThread *thread = vm->GetJSThread(); JSHandle parentValue = JSNApiHelper::ToJSHandle(parent); JSHandle parentHandle = JSHandle::Cast(parentValue); JSHandle thisHandle = JSHandle::Cast(JSNApiHelper::ToJSHandle(this)); // Set this.__proto__ to parent bool res = JSObject::SetPrototype(thread, thisHandle, parentValue); if (!res) { return false; } // Set this.Prototype.__proto__ to parent.Prototype JSHandle parentProtoType(thread, JSFunction::PrototypeGetter(thread, parentHandle)); JSHandle thisProtoType(thread, JSFunction::PrototypeGetter(thread, thisHandle)); return JSObject::SetPrototype(thread, JSHandle::Cast(thisProtoType), parentProtoType); } void FunctionRef::SetName(const EcmaVM *vm, Local name) { [[maybe_unused]] LocalScope scope(vm); JSThread *thread = vm->GetJSThread(); JSFunction *func = JSFunction::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject()); JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name); JSFunction::SetFunctionNameNoPrefix(thread, func, key); } Local FunctionRef::GetName(const EcmaVM *vm) { EscapeLocalScope scope(vm); JSThread *thread = vm->GetJSThread(); JSHandle func = JSHandle(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle name = JSFunctionBase::GetFunctionName(thread, func); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return scope.Escape(JSNApiHelper::ToLocal(name)); } Local FunctionRef::GetSourceCode(const EcmaVM *vm, int lineNumber) { EscapeLocalScope scope(vm); JSThread *thread = vm->GetJSThread(); JSHandle func = JSHandle(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle method = JSHandle(thread, func->GetMethod()); const JSPandaFile *jsPandaFile = method->GetJSPandaFile(); DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile); ecmascript::CString entry = JSPandaFile::ENTRY_FUNCTION_NAME; if (!jsPandaFile->IsBundlePack()) { JSFunction *function = JSFunction::Cast(func.GetTaggedValue().GetTaggedObject()); JSTaggedValue recordName = function->GetRecordName(); ASSERT(!recordName.IsHole()); entry = ConvertToString(recordName); } uint32_t mainMethodIndex = jsPandaFile->GetMainMethodIndex(entry); JSMutableHandle sourceCodeHandle(thread, BuiltinsBase::GetTaggedString(thread, "")); if (mainMethodIndex == 0) { return scope.Escape(JSNApiHelper::ToLocal(sourceCodeHandle)); } const std::string &allSourceCode = debugExtractor->GetSourceCode(panda_file::File::EntityId(mainMethodIndex)); std::string sourceCode = StringHelper::GetSpecifiedLine(allSourceCode, lineNumber); uint32_t codeLen = sourceCode.length(); if (codeLen == 0) { return scope.Escape(JSNApiHelper::ToLocal(sourceCodeHandle)); } if (sourceCode[codeLen - 1] == '\r') { sourceCode = sourceCode.substr(0, codeLen - 1); } sourceCodeHandle.Update(BuiltinsBase::GetTaggedString(thread, sourceCode.c_str())); return scope.Escape(JSNApiHelper::ToLocal(sourceCodeHandle)); } bool FunctionRef::IsNative(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle func = JSHandle(thread, JSNApiHelper::ToJSTaggedValue(this)); JSHandle method = JSHandle(thread, func->GetMethod()); return method->IsNativeWithCallField(); } // ----------------------------------- ArrayRef ---------------------------------------- Local ArrayRef::New(const EcmaVM *vm, uint32_t length) { JSThread *thread = vm->GetJSThread(); JSTaggedNumber arrayLen(length); JSHandle array = JSArray::ArrayCreate(thread, arrayLen); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(array); } int32_t ArrayRef::Length([[maybe_unused]] const EcmaVM *vm) { return JSArray::Cast(JSNApiHelper::ToJSTaggedValue(this).GetTaggedObject())->GetArrayLength(); } Local ArrayRef::GetValueAt(const EcmaVM *vm, Local obj, uint32_t index) { JSThread *thread = vm->GetJSThread(); JSHandle object = JSNApiHelper::ToJSHandle(obj); JSHandle result = JSArray::FastGetPropertyByValue(thread, object, index); return JSNApiHelper::ToLocal(result); } bool ArrayRef::SetValueAt(const EcmaVM *vm, Local obj, uint32_t index, Local value) { JSThread *thread = vm->GetJSThread(); JSHandle objectHandle = JSNApiHelper::ToJSHandle(obj); JSHandle valueHandle = JSNApiHelper::ToJSHandle(value); return JSArray::FastSetPropertyByValue(thread, objectHandle, index, valueHandle); } // ---------------------------------- Promise -------------------------------------- Local PromiseCapabilityRef::New(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle constructor(globalEnv->GetPromiseFunction()); JSHandle capability(JSPromise::NewPromiseCapability(thread, constructor)); return JSNApiHelper::ToLocal(capability); } Local PromiseCapabilityRef::GetPromise(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle capacity(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(thread, capacity->GetPromise())); } bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, Local value) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle arg = JSNApiHelper::ToJSHandle(value); JSHandle capacity(JSNApiHelper::ToJSHandle(this)); JSHandle resolve(thread, capacity->GetResolve()); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefined, undefined, 1); RETURN_VALUE_IF_ABRUPT(thread, false); info->SetCallArg(arg.GetTaggedValue()); JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT(thread, false); EcmaVM::ConstCast(vm)->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); vm->GetHeap()->ClearKeptObjects(); return true; } bool PromiseCapabilityRef::Reject(const EcmaVM *vm, Local reason) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle arg = JSNApiHelper::ToJSHandle(reason); JSHandle capacity(JSNApiHelper::ToJSHandle(this)); JSHandle reject(thread, capacity->GetReject()); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefined, undefined, 1); RETURN_VALUE_IF_ABRUPT(thread, false); info->SetCallArg(arg.GetTaggedValue()); JSFunction::Call(info); RETURN_VALUE_IF_ABRUPT(thread, false); EcmaVM::ConstCast(vm)->ExecutePromisePendingJob(); RETURN_VALUE_IF_ABRUPT(thread, false); vm->GetHeap()->ClearKeptObjects(); return true; } Local PromiseRef::Catch(const EcmaVM *vm, Local handler) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle catchKey(thread, constants->GetPromiseCatchString()); JSHandle reject = JSNApiHelper::ToJSHandle(handler); JSHandle undefined = constants->GetHandledUndefined(); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 1); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); info->SetCallArg(reject.GetTaggedValue()); JSTaggedValue result = JSFunction::Invoke(info, catchKey); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::Finally(const EcmaVM *vm, Local handler) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle finallyKey = constants->GetHandledPromiseFinallyString(); JSHandle resolver = JSNApiHelper::ToJSHandle(handler); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 2); // 2: two args RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); info->SetCallArg(resolver.GetTaggedValue(), undefined.GetTaggedValue()); JSTaggedValue result = JSFunction::Invoke(info, finallyKey); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::Then(const EcmaVM *vm, Local handler) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle thenKey(thread, constants->GetPromiseThenString()); JSHandle resolver = JSNApiHelper::ToJSHandle(handler); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 2); // 2: two args RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); info->SetCallArg(resolver.GetTaggedValue(), undefined.GetTaggedValue()); JSTaggedValue result = JSFunction::Invoke(info, thenKey); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } Local PromiseRef::Then(const EcmaVM *vm, Local onFulfilled, Local onRejected) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle thenKey(thread, constants->GetPromiseThenString()); JSHandle resolver = JSNApiHelper::ToJSHandle(onFulfilled); JSHandle reject = JSNApiHelper::ToJSHandle(onRejected); JSHandle undefined(constants->GetHandledUndefined()); EcmaRuntimeCallInfo *info = ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, promise, undefined, 2); // 2: two args RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); info->SetCallArg(resolver.GetTaggedValue(), reject.GetTaggedValue()); JSTaggedValue result = JSFunction::Invoke(info, thenKey); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); } // ---------------------------------- Promise ------------------------------------- // ---------------------------------- Buffer ----------------------------------- Local ArrayBufferRef::New(const EcmaVM *vm, int32_t length) { ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(length); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } Local ArrayBufferRef::New( const EcmaVM *vm, void *buffer, int32_t length, const Deleter &deleter, void *data) { ObjectFactory *factory = vm->GetFactory(); JSHandle arrayBuffer = factory->NewJSArrayBuffer(buffer, length, reinterpret_cast(deleter), data); return JSNApiHelper::ToLocal(JSHandle(arrayBuffer)); } int32_t ArrayBufferRef::ByteLength([[maybe_unused]] const EcmaVM *vm) { JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); return arrayBuffer->GetArrayBufferByteLength(); } void *ArrayBufferRef::GetBuffer() { JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(this)); JSTaggedValue bufferData = arrayBuffer->GetArrayBufferData(); if (!bufferData.IsJSNativePointer()) { return nullptr; } return JSNativePointer::Cast(bufferData.GetTaggedObject())->GetExternalPointer(); } // ---------------------------------- Buffer ----------------------------------- // ---------------------------------- DataView ----------------------------------- Local DataViewRef::New( const EcmaVM *vm, Local arrayBuffer, uint32_t byteOffset, uint32_t byteLength) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle buffer(JSNApiHelper::ToJSHandle(arrayBuffer)); JSHandle dataView = factory->NewJSDataView(buffer, byteOffset, byteLength); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(JSHandle(dataView)); } uint32_t DataViewRef::ByteLength() { JSHandle dataView(JSNApiHelper::ToJSHandle(this)); return dataView->GetByteLength(); } uint32_t DataViewRef::ByteOffset() { JSHandle dataView(JSNApiHelper::ToJSHandle(this)); return dataView->GetByteOffset(); } Local DataViewRef::GetArrayBuffer(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle dataView(JSNApiHelper::ToJSHandle(this)); JSHandle arrayBuffer(thread, dataView->GetViewedArrayBuffer()); return JSNApiHelper::ToLocal(arrayBuffer); } // ---------------------------------- DataView ----------------------------------- // ---------------------------------- TypedArray ----------------------------------- uint32_t TypedArrayRef::ByteLength([[maybe_unused]] const EcmaVM *vm) { JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); return typedArray->GetByteLength(); } uint32_t TypedArrayRef::ByteOffset([[maybe_unused]] const EcmaVM *vm) { JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); return typedArray->GetByteOffset(); } uint32_t TypedArrayRef::ArrayLength([[maybe_unused]] const EcmaVM *vm) { JSHandle typedArray(JSNApiHelper::ToJSHandle(this)); return typedArray->GetArrayLength(); } Local TypedArrayRef::GetArrayBuffer(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle typeArray(JSNApiHelper::ToJSHandle(this)); JSHandle arrayBuffer(thread, JSTypedArray::GetOffHeapBuffer(thread, typeArray)); return JSNApiHelper::ToLocal(arrayBuffer); } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define TYPED_ARRAY_NEW(Type) \ Local Type##Ref::New( \ const EcmaVM *vm, Local buffer, int32_t byteOffset, int32_t length) \ { \ JSThread *thread = vm->GetJSThread(); \ JSHandle env = vm->GetGlobalEnv(); \ \ JSHandle func = env->Get##Type##Function(); \ JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(buffer)); \ JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); \ const int32_t argsLength = 3; \ EcmaRuntimeCallInfo *info = \ ecmascript::EcmaInterpreter::NewRuntimeCallInfo(thread, func, undefined, func, argsLength); \ RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); \ info->SetCallArg(arrayBuffer.GetTaggedValue(), JSTaggedValue(byteOffset), JSTaggedValue(length)); \ JSTaggedValue result = JSFunction::Construct(info); \ RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); \ JSHandle resultHandle(thread, result); \ return JSNApiHelper::ToLocal(resultHandle); \ } TYPED_ARRAY_ALL(TYPED_ARRAY_NEW) #undef TYPED_ARRAY_NEW // ---------------------------------- TypedArray ----------------------------------- // ---------------------------------- Error --------------------------------------- // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EXCEPTION_ERROR_NEW(name, type) \ Local Exception::name(const EcmaVM *vm, Local message) \ { \ JSThread *thread = vm->GetJSThread(); \ if (thread->HasPendingException()) { \ thread->ClearException(); \ } \ ObjectFactory *factory = vm->GetFactory(); \ \ JSHandle messageValue(JSNApiHelper::ToJSHandle(message)); \ JSHandle result(factory->NewJSError(ErrorType::type, messageValue)); \ return JSNApiHelper::ToLocal(result); \ } EXCEPTION_ERROR_ALL(EXCEPTION_ERROR_NEW) #undef EXCEPTION_ERROR_NEW // ---------------------------------- Error --------------------------------------- // ---------------------------------- JSON ------------------------------------------ Local JSON::Parse(const EcmaVM *vm, Local string) { JSThread *thread = vm->GetJSThread(); auto ecmaStr = EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject()); JSHandle result; if (EcmaStringAccessor(ecmaStr).IsUtf8()) { JsonParser parser(thread); result = parser.ParseUtf8(EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject())); } else { JsonParser parser(thread); result = parser.ParseUtf16(EcmaString::Cast(JSNApiHelper::ToJSTaggedValue(*string).GetTaggedObject())); } RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(result); } Local JSON::Stringify(const EcmaVM *vm, Local json) { JSThread *thread = vm->GetJSThread(); auto constants = thread->GlobalConstants(); JsonStringifier stringifier(thread); JSHandle str = stringifier.Stringify( JSNApiHelper::ToJSHandle(json), constants->GetHandledUndefined(), constants->GetHandledUndefined()); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(str); } Local RegExpRef::GetOriginalSource(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue source = regExp->GetOriginalSource(); if (!source.IsString()) { auto constants = thread->GlobalConstants(); return JSNApiHelper::ToLocal(constants->GetHandledEmptyString()); } JSHandle sourceHandle(thread, source); return JSNApiHelper::ToLocal(sourceHandle); } std::string RegExpRef::GetOriginalFlags() { JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue regExpFlags = regExp->GetOriginalFlags(); uint32_t regExpFlagsInt = static_cast(regExpFlags.GetInt()); std::string strFlags = ""; if (regExpFlagsInt & RegExpParser::FLAG_GLOBAL) { strFlags += "g"; } if (regExpFlagsInt & RegExpParser::FLAG_IGNORECASE) { strFlags += "i"; } if (regExpFlagsInt & RegExpParser::FLAG_MULTILINE) { strFlags += "m"; } if (regExpFlagsInt & RegExpParser::FLAG_DOTALL) { strFlags += "s"; } if (regExpFlagsInt & RegExpParser::FLAG_UTF16) { strFlags += "u"; } if (regExpFlagsInt & RegExpParser::FLAG_STICKY) { strFlags += "y"; } std::sort(strFlags.begin(), strFlags.end()); return strFlags; } Local RegExpRef::IsGlobal(const EcmaVM *vm) { JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue flags = regExp->GetOriginalFlags(); bool result = flags.GetInt() & RegExpParser::FLAG_GLOBAL; Local jsValue = BooleanRef::New(vm, result); return jsValue; } Local RegExpRef::IsIgnoreCase(const EcmaVM *vm) { JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue flags = regExp->GetOriginalFlags(); bool result = flags.GetInt() & RegExpParser::FLAG_IGNORECASE; Local jsValue = BooleanRef::New(vm, result); return jsValue; } Local RegExpRef::IsMultiline(const EcmaVM *vm) { JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue flags = regExp->GetOriginalFlags(); bool result = flags.GetInt() & RegExpParser::FLAG_MULTILINE; Local jsValue = BooleanRef::New(vm, result); return jsValue; } Local RegExpRef::IsDotAll(const EcmaVM *vm) { JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue flags = regExp->GetOriginalFlags(); bool result = flags.GetInt() & RegExpParser::FLAG_DOTALL; Local jsValue = BooleanRef::New(vm, result); return jsValue; } Local RegExpRef::IsUtf16(const EcmaVM *vm) { JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue flags = regExp->GetOriginalFlags(); bool result = flags.GetInt() & RegExpParser::FLAG_UTF16; Local jsValue = BooleanRef::New(vm, result); return jsValue; } Local RegExpRef::IsStick(const EcmaVM *vm) { JSHandle regExp(JSNApiHelper::ToJSHandle(this)); JSTaggedValue flags = regExp->GetOriginalFlags(); bool result = flags.GetInt() & RegExpParser::FLAG_STICKY; Local jsValue = BooleanRef::New(vm, result); return jsValue; } Local DateRef::New(const EcmaVM *vm, double time) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = vm->GetFactory(); JSHandle globalEnv = vm->GetGlobalEnv(); JSHandle dateFunction(globalEnv->GetDateFunction()); JSHandle dateObject(factory->NewJSObjectByConstructor(dateFunction)); dateObject->SetTimeValue(thread, JSTaggedValue(time)); return JSNApiHelper::ToLocal(JSHandle(dateObject)); } Local DateRef::ToString(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle date(JSNApiHelper::ToJSHandle(this)); JSTaggedValue dateStr = date->ToString(thread); if (!dateStr.IsString()) { auto constants = thread->GlobalConstants(); return JSNApiHelper::ToLocal(constants->GetHandledEmptyString()); } JSHandle dateStrHandle(thread, dateStr); return JSNApiHelper::ToLocal(dateStrHandle); } double DateRef::GetTime() { JSHandle date(JSNApiHelper::ToJSHandle(this)); if (!date->IsDate()) { LOG_ECMA(ERROR) << "Not a Date Object"; } return date->GetTime().GetDouble(); } Local MapRef::Get(const EcmaVM *vm, Local key) { JSHandle map(JSNApiHelper::ToJSHandle(this)); return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), map->Get(JSNApiHelper::ToJSTaggedValue(*key)))); } void MapRef::Set(const EcmaVM *vm, Local key, Local value) { JSHandle map(JSNApiHelper::ToJSHandle(this)); JSMap::Set(vm->GetJSThread(), map, JSNApiHelper::ToJSHandle(key), JSNApiHelper::ToJSHandle(value)); } Local MapRef::New(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsMapFunction(); JSHandle map = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle hashMap = LinkedHashMap::Create(thread); map->SetLinkedMap(thread, hashMap); JSHandle mapTag = JSHandle::Cast(map); return JSNApiHelper::ToLocal(mapTag); } int32_t MapRef::GetSize() { JSHandle map(JSNApiHelper::ToJSHandle(this)); return map->GetSize(); } int32_t MapRef::GetTotalElements() { JSHandle map(JSNApiHelper::ToJSHandle(this)); return map->GetSize() + LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())->NumberOfDeletedElements(); } Local MapRef::GetKey(const EcmaVM *vm, int entry) { JSHandle map(JSNApiHelper::ToJSHandle(this)); JSThread *thread = vm->GetJSThread(); return JSNApiHelper::ToLocal(JSHandle(thread, map->GetKey(entry))); } Local MapRef::GetValue(const EcmaVM *vm, int entry) { JSHandle map(JSNApiHelper::ToJSHandle(this)); JSThread *thread = vm->GetJSThread(); return JSNApiHelper::ToLocal(JSHandle(thread, map->GetValue(entry))); } int32_t SetRef::GetSize() { JSHandle set(JSNApiHelper::ToJSHandle(this)); return set->GetSize(); } int32_t SetRef::GetTotalElements() { JSHandle set(JSNApiHelper::ToJSHandle(this)); return set->GetSize() + LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())->NumberOfDeletedElements(); } Local SetRef::GetValue(const EcmaVM *vm, int entry) { JSHandle set(JSNApiHelper::ToJSHandle(this)); JSThread *thread = vm->GetJSThread(); return JSNApiHelper::ToLocal(JSHandle(thread, set->GetValue(entry))); } int32_t MapIteratorRef::GetIndex() { JSHandle jsMapIter(JSNApiHelper::ToJSHandle(this)); return jsMapIter->GetNextIndex(); } Local MapIteratorRef::GetKind(const EcmaVM *vm) { JSHandle jsMapIter(JSNApiHelper::ToJSHandle(this)); IterationKind iterKind = jsMapIter->GetIterationKind(); Local result; switch (iterKind) { case IterationKind::KEY: result = StringRef::NewFromUtf8(vm, "keys"); break; case IterationKind::VALUE: result = StringRef::NewFromUtf8(vm, "values"); break; case IterationKind::KEY_AND_VALUE: result = StringRef::NewFromUtf8(vm, "entries"); break; default: break; } return result; } int32_t SetIteratorRef::GetIndex() { JSHandle jsSetIter(JSNApiHelper::ToJSHandle(this)); return jsSetIter->GetNextIndex(); } Local SetIteratorRef::GetKind(const EcmaVM *vm) { JSHandle jsSetIter(JSNApiHelper::ToJSHandle(this)); IterationKind iterKind = jsSetIter->GetIterationKind(); Local result; switch (iterKind) { case IterationKind::KEY: result = StringRef::NewFromUtf8(vm, "keys"); break; case IterationKind::VALUE: result = StringRef::NewFromUtf8(vm, "values"); break; case IterationKind::KEY_AND_VALUE: result = StringRef::NewFromUtf8(vm, "entries"); break; default: break; } return result; } bool GeneratorFunctionRef::IsGenerator() { return IsGeneratorFunction(); } Local GeneratorObjectRef::GetGeneratorState(const EcmaVM *vm) { JSHandle jsGenerator(JSNApiHelper::ToJSHandle(this)); if (jsGenerator->GetGeneratorState() == JSGeneratorState::COMPLETED) { return StringRef::NewFromUtf8(vm, "closed"); } return StringRef::NewFromUtf8(vm, "suspended"); } Local GeneratorObjectRef::GetGeneratorFunction(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle jsGenerator(JSNApiHelper::ToJSHandle(this)); JSHandle generatorContext(thread, jsGenerator->GetGeneratorContext()); JSTaggedValue jsTagValue = generatorContext->GetMethod(); return JSNApiHelper::ToLocal(JSHandle(thread, jsTagValue)); } Local GeneratorObjectRef::GetGeneratorReceiver(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle jsGenerator(JSNApiHelper::ToJSHandle(this)); JSHandle generatorContext(thread, jsGenerator->GetGeneratorContext()); JSTaggedValue jsTagValue = generatorContext->GetAcc(); return JSNApiHelper::ToLocal(JSHandle(thread, jsTagValue)); } Local CollatorRef::GetCompareFunction(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle jsCollator(JSNApiHelper::ToJSHandle(this)); JSTaggedValue jsTagValue = jsCollator->GetBoundCompare(); return JSNApiHelper::ToLocal(JSHandle(thread, jsTagValue)); } Local DataTimeFormatRef::GetFormatFunction(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle jsDateTimeFormat(JSNApiHelper::ToJSHandle(this)); JSTaggedValue jsTagValue = jsDateTimeFormat->GetBoundFormat(); return JSNApiHelper::ToLocal(JSHandle(thread, jsTagValue)); } Local NumberFormatRef::GetFormatFunction(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle jsNumberFormat(JSNApiHelper::ToJSHandle(this)); JSTaggedValue jsTagValue = jsNumberFormat->GetBoundFormat(); return JSNApiHelper::ToLocal(JSHandle(thread, jsTagValue)); } // ----------------------------------- FunctionCallback --------------------------------- JSTaggedValue Callback::RegisterCallback(ecmascript::EcmaRuntimeCallInfo *ecmaRuntimeCallInfo) { // Constructor JSThread *thread = ecmaRuntimeCallInfo->GetThread(); JSHandle constructor = BuiltinsBase::GetConstructor(ecmaRuntimeCallInfo); if (!constructor->IsJSFunction()) { return JSTaggedValue::False(); } [[maybe_unused]] LocalScope scope(thread->GetEcmaVM()); JSHandle function(constructor); JSTaggedValue extraInfoValue = function->GetFunctionExtraInfo(); if (!extraInfoValue.IsJSNativePointer()) { return JSTaggedValue::False(); } JSHandle extraInfo(thread, extraInfoValue); // callBack FunctionCallback nativeFunc = reinterpret_cast(extraInfo->GetExternalPointer()); JsiRuntimeCallInfo jsiRuntimeCallInfo(ecmaRuntimeCallInfo, extraInfo->GetData()); #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) if (thread->GetCallNapiGetStack() && function->IsCallNapi()) { thread->GetEcmaVM()->GetProfiler()->GetStackCallNapi(thread, true); } #endif Local result = nativeFunc(&jsiRuntimeCallInfo); #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) if (thread->GetCallNapiGetStack() && function->IsCallNapi()) { thread->GetEcmaVM()->GetProfiler()->GetStackCallNapi(thread, false); } #endif return JSNApiHelper::ToJSHandle(result).GetTaggedValue(); } // ------------------------------------- JSExecutionScope ------------------------------ JSExecutionScope::JSExecutionScope(const EcmaVM *vm) { (void)vm; } JSExecutionScope::~JSExecutionScope() { last_current_thread_ = nullptr; is_revert_ = false; } // ----------------------------------- JSValueRef -------------------------------------- Local JSValueRef::Undefined(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); const GlobalEnvConstants *constants = thread->GlobalConstants(); return JSNApiHelper::ToLocal(constants->GetHandledUndefined()); } Local JSValueRef::Null(const EcmaVM *vm) { return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), JSTaggedValue::Null())); } Local JSValueRef::True(const EcmaVM *vm) { return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), JSTaggedValue::True())); } Local JSValueRef::False(const EcmaVM *vm) { return JSNApiHelper::ToLocal(JSHandle(vm->GetJSThread(), JSTaggedValue::False())); } Local JSValueRef::ToObject(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); if (IsUndefined() || IsNull()) { return Undefined(vm); } JSHandle obj(JSTaggedValue::ToObject(thread, JSNApiHelper::ToJSHandle(this))); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(obj); } Local JSValueRef::ToString(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); if (!obj->IsString()) { obj = JSHandle(JSTaggedValue::ToString(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); } return JSNApiHelper::ToLocal(obj); } Local JSValueRef::ToNativePointer(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(obj); } bool JSValueRef::BooleaValue() { return JSNApiHelper::ToJSTaggedValue(this).ToBoolean(); } int64_t JSValueRef::IntegerValue(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle tagged = JSNApiHelper::ToJSHandle(this); if (tagged->IsNumber()) { if (!NumberHelper::IsFinite(tagged.GetTaggedValue()) || NumberHelper::IsNaN(tagged.GetTaggedValue())) { return 0; } else { return NumberHelper::DoubleToInt64(tagged->GetNumber()); } } JSTaggedNumber number = JSTaggedValue::ToInteger(thread, tagged); RETURN_VALUE_IF_ABRUPT(thread, 0); return NumberHelper::DoubleToInt64(number.GetNumber()); } uint32_t JSValueRef::Uint32Value(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); uint32_t number = JSTaggedValue::ToUint32(thread, JSNApiHelper::ToJSHandle(this)); RETURN_VALUE_IF_ABRUPT(thread, 0); return number; } int32_t JSValueRef::Int32Value(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); int32_t number = JSTaggedValue::ToInt32(thread, JSNApiHelper::ToJSHandle(this)); RETURN_VALUE_IF_ABRUPT(thread, 0); return number; } Local JSValueRef::ToBoolean(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle booleanObj = JSHandle(thread, JSTaggedValue(obj->ToBoolean())); return JSNApiHelper::ToLocal(booleanObj); } Local JSValueRef::ToNumber(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSHandle obj = JSNApiHelper::ToJSHandle(this); JSHandle number(thread, JSTaggedValue::ToNumber(thread, obj)); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Undefined(vm)); return JSNApiHelper::ToLocal(number); } bool JSValueRef::IsStrictEquals(const EcmaVM *vm, Local value) { JSThread *thread = vm->GetJSThread(); JSHandle xValue = JSNApiHelper::ToJSHandle(this); JSHandle yValue = JSNApiHelper::ToJSHandle(value); return JSTaggedValue::StrictEqual(thread, xValue, yValue); } Local JSValueRef::Typeof(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); JSTaggedValue value = FastRuntimeStub::FastTypeOf(thread, JSNApiHelper::ToJSTaggedValue(this)); return JSNApiHelper::ToLocal(JSHandle(thread, value)); } bool JSValueRef::InstanceOf(const EcmaVM *vm, Local value) { JSThread *thread = vm->GetJSThread(); JSHandle origin = JSNApiHelper::ToJSHandle(this); JSHandle target = JSNApiHelper::ToJSHandle(value); bool result = JSObject::InstanceOf(thread, origin, target); RETURN_VALUE_IF_ABRUPT(thread, false); return result; } bool JSValueRef::IsUndefined() { return JSNApiHelper::ToJSTaggedValue(this).IsUndefined(); } bool JSValueRef::IsNull() { return JSNApiHelper::ToJSTaggedValue(this).IsNull(); } bool JSValueRef::IsHole() { return JSNApiHelper::ToJSTaggedValue(this).IsHole(); } bool JSValueRef::IsTrue() { return JSNApiHelper::ToJSTaggedValue(this).IsTrue(); } bool JSValueRef::IsFalse() { return JSNApiHelper::ToJSTaggedValue(this).IsFalse(); } bool JSValueRef::IsNumber() { return JSNApiHelper::ToJSTaggedValue(this).IsNumber(); } bool JSValueRef::IsBigInt() { return JSNApiHelper::ToJSTaggedValue(this).IsBigInt(); } bool JSValueRef::IsInt() { return JSNApiHelper::ToJSTaggedValue(this).IsInt(); } bool JSValueRef::WithinInt32() { return JSNApiHelper::ToJSTaggedValue(this).WithinInt32(); } bool JSValueRef::IsBoolean() { return JSNApiHelper::ToJSTaggedValue(this).IsBoolean(); } bool JSValueRef::IsString() { return JSNApiHelper::ToJSTaggedValue(this).IsString(); } bool JSValueRef::IsSymbol() { return JSNApiHelper::ToJSTaggedValue(this).IsSymbol(); } bool JSValueRef::IsObject() { return JSNApiHelper::ToJSTaggedValue(this).IsECMAObject(); } bool JSValueRef::IsArray(const EcmaVM *vm) { JSThread *thread = vm->GetJSThread(); return JSNApiHelper::ToJSTaggedValue(this).IsArray(thread); } bool JSValueRef::IsConstructor() { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsHeapObject() && value.IsConstructor(); } bool JSValueRef::IsFunction() { JSTaggedValue value = JSNApiHelper::ToJSTaggedValue(this); return value.IsHeapObject() && value.IsCallable(); } bool JSValueRef::IsProxy() { return JSNApiHelper::ToJSTaggedValue(this).IsJSProxy(); } bool JSValueRef::IsPromise() { return JSNApiHelper::ToJSTaggedValue(this).IsJSPromise(); } bool JSValueRef::IsDataView() { return JSNApiHelper::ToJSTaggedValue(this).IsDataView(); } bool JSValueRef::IsTypedArray() { return JSNApiHelper::ToJSTaggedValue(this).IsTypedArray(); } bool JSValueRef::IsNativePointer() { return JSNApiHelper::ToJSTaggedValue(this).IsJSNativePointer(); } bool JSValueRef::IsDate() { return JSNApiHelper::ToJSTaggedValue(this).IsDate(); } bool JSValueRef::IsError() { return JSNApiHelper::ToJSTaggedValue(this).IsJSError(); } bool JSValueRef::IsMap() { return JSNApiHelper::ToJSTaggedValue(this).IsJSMap(); } bool JSValueRef::IsSet() { return JSNApiHelper::ToJSTaggedValue(this).IsJSSet(); } bool JSValueRef::IsWeakRef() { return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakRef(); } bool JSValueRef::IsWeakMap() { return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakMap(); } bool JSValueRef::IsWeakSet() { return JSNApiHelper::ToJSTaggedValue(this).IsJSWeakSet(); } bool JSValueRef::IsRegExp() { return JSNApiHelper::ToJSTaggedValue(this).IsJSRegExp(); } bool JSValueRef::IsArrayIterator() { return JSNApiHelper::ToJSTaggedValue(this).IsJSArrayIterator(); } bool JSValueRef::IsStringIterator() { return JSNApiHelper::ToJSTaggedValue(this).IsStringIterator(); } bool JSValueRef::IsSetIterator() { return JSNApiHelper::ToJSTaggedValue(this).IsJSSetIterator(); } bool JSValueRef::IsMapIterator() { return JSNApiHelper::ToJSTaggedValue(this).IsJSMapIterator(); } bool JSValueRef::IsArrayBuffer() { return JSNApiHelper::ToJSTaggedValue(this).IsArrayBuffer(); } bool JSValueRef::IsUint8Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSUint8Array(); } bool JSValueRef::IsInt8Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSInt8Array(); } bool JSValueRef::IsUint8ClampedArray() { return JSNApiHelper::ToJSTaggedValue(this).IsJSUint8ClampedArray(); } bool JSValueRef::IsInt16Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSInt16Array(); } bool JSValueRef::IsUint16Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSUint16Array(); } bool JSValueRef::IsInt32Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSInt32Array(); } bool JSValueRef::IsUint32Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSUint32Array(); } bool JSValueRef::IsFloat32Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSFloat32Array(); } bool JSValueRef::IsFloat64Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSFloat64Array(); } bool JSValueRef::IsBigInt64Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSBigInt64Array(); } bool JSValueRef::IsBigUint64Array() { return JSNApiHelper::ToJSTaggedValue(this).IsJSBigUint64Array(); } bool JSValueRef::IsJSPrimitiveRef() { return JSNApiHelper::ToJSTaggedValue(this).IsJSPrimitiveRef(); } bool JSValueRef::IsJSPrimitiveNumber() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsNumber(); } bool JSValueRef::IsJSPrimitiveInt() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsInt(); } bool JSValueRef::IsJSPrimitiveBoolean() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsBoolean(); } bool JSValueRef::IsJSPrimitiveString() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsString(); } bool JSValueRef::IsJSPrimitiveSymbol() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return JSPrimitiveRef::Cast(obj->GetTaggedObject())->IsSymbol(); } bool JSValueRef::IsGeneratorObject() { JSHandle obj = JSNApiHelper::ToJSHandle(this); bool rst = obj->IsGeneratorObject(); return rst; } bool JSValueRef::IsModuleNamespaceObject() { JSHandle obj = JSNApiHelper::ToJSHandle(this); bool rst = obj->IsModuleNamespace(); return rst; } bool JSValueRef::IsSharedArrayBuffer() { JSHandle obj = JSNApiHelper::ToJSHandle(this); bool rst = obj->IsSharedArrayBuffer(); return rst; } bool JSValueRef::IsJSLocale() { return JSNApiHelper::ToJSTaggedValue(this).IsJSLocale(); } bool JSValueRef::IsJSDateTimeFormat() { return JSNApiHelper::ToJSTaggedValue(this).IsJSDateTimeFormat(); } bool JSValueRef::IsJSRelativeTimeFormat() { return JSNApiHelper::ToJSTaggedValue(this).IsJSRelativeTimeFormat(); } bool JSValueRef::IsJSIntl() { return JSNApiHelper::ToJSTaggedValue(this).IsJSIntl(); } bool JSValueRef::IsJSNumberFormat() { return JSNApiHelper::ToJSTaggedValue(this).IsJSNumberFormat(); } bool JSValueRef::IsJSCollator() { return JSNApiHelper::ToJSTaggedValue(this).IsJSCollator(); } bool JSValueRef::IsJSPluralRules() { return JSNApiHelper::ToJSTaggedValue(this).IsJSPluralRules(); } bool JSValueRef::IsJSListFormat() { return JSNApiHelper::ToJSTaggedValue(this).IsJSListFormat(); } bool JSValueRef::IsAsyncGeneratorObject() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return obj->IsAsyncGeneratorObject(); } bool JSValueRef::IsAsyncFunction() { JSHandle obj = JSNApiHelper::ToJSHandle(this); bool rst = obj->IsJSAsyncFunction(); return rst; } bool JSValueRef::IsArgumentsObject() { JSHandle obj = JSNApiHelper::ToJSHandle(this); bool rst = obj->IsArguments(); return rst; } bool JSValueRef::IsGeneratorFunction() { JSHandle obj = JSNApiHelper::ToJSHandle(this); bool rst = obj->IsGeneratorFunction(); return rst; } bool JSValueRef::IsAsyncGeneratorFunction() { JSHandle obj = JSNApiHelper::ToJSHandle(this); return obj->IsAsyncGeneratorFunction(); } // ------------------------------------ JsiRuntimeCallInfo ----------------------------------------------- JsiRuntimeCallInfo::JsiRuntimeCallInfo(ecmascript::EcmaRuntimeCallInfo* ecmaInfo, void* data) : thread_(ecmaInfo->GetThread()), numArgs_(ecmaInfo->GetArgsNumber()) { stackArgs_ = ecmaInfo->GetArgs(); data_ = data; } EcmaVM *JsiRuntimeCallInfo::GetVM() const { return thread_->GetEcmaVM(); } // ---------------------------------------Hot Patch---------------------------------------------------- bool JSNApi::LoadPatch(EcmaVM *vm, const std::string &patchFileName, const std::string &baseFileName) { ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); JSThread *thread = vm->GetJSThread(); return quickFixManager->LoadPatch(thread, patchFileName, baseFileName); } bool JSNApi::LoadPatch(EcmaVM *vm, const std::string &patchFileName, const void *patchBuffer, size_t patchSize, const std::string &baseFileName) { ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); JSThread *thread = vm->GetJSThread(); return quickFixManager->LoadPatch(thread, patchFileName, patchBuffer, patchSize, baseFileName); } bool JSNApi::UnloadPatch(EcmaVM *vm, const std::string &patchFileName) { ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); JSThread *thread = vm->GetJSThread(); return quickFixManager->UnloadPatch(thread, patchFileName); } /* * check whether the exception is caused by quickfix methods. */ bool JSNApi::IsQuickFixCausedException(EcmaVM *vm, Local exception, const std::string &patchFileName) { if (exception.IsEmpty()) { return false; } ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); JSThread *thread = vm->GetJSThread(); JSHandle exceptionInfo = JSNApiHelper::ToJSHandle(exception); return quickFixManager->IsQuickFixCausedException(thread, exceptionInfo, patchFileName); } /* * register quickfix query function. */ void JSNApi::RegisterQuickFixQueryFunc(EcmaVM *vm, QuickFixQueryCallBack callBack) { ecmascript::QuickFixManager *quickFixManager = vm->GetQuickFixManager(); quickFixManager->RegisterQuickFixQueryFunc(callBack); } bool JSNApi::IsBundle(EcmaVM *vm) { return vm->IsBundlePack(); } void JSNApi::SetBundle(EcmaVM *vm, bool value) { vm->SetIsBundlePack(value); } // note: The function SetAssetPath is a generic interface for previewing and physical machines. void JSNApi::SetAssetPath(EcmaVM *vm, const std::string &assetPath) { ecmascript::CString path = assetPath.c_str(); vm->SetAssetPath(path); } std::string JSNApi::GetAssetPath(EcmaVM *vm) { return vm->GetAssetPath().c_str(); } void JSNApi::SetBundleName(EcmaVM *vm, std::string bundleName) { ecmascript::CString name = bundleName.c_str(); vm->SetBundleName(name); } std::string JSNApi::GetBundleName(EcmaVM *vm) { return vm->GetBundleName().c_str(); } void JSNApi::SetModuleName(EcmaVM *vm, std::string moduleName) { ecmascript::CString name = moduleName.c_str(); vm->SetModuleName(name); } std::string JSNApi::GetModuleName(EcmaVM *vm) { return vm->GetModuleName().c_str(); } void JSNApi::SetLoop(EcmaVM *vm, void *loop) { vm->SetLoop(loop); } bool JSNApi::InitForConcurrentThread(EcmaVM *vm, ConcurrentCallback cb, void *data) { vm->SetConcurrentCallback(cb, data); return true; } bool JSNApi::InitForConcurrentFunction(EcmaVM *vm, Local function) { [[maybe_unused]] LocalScope scope(vm); JSHandle funcVal = JSNApiHelper::ToJSHandle(function); JSHandle transFunc = JSHandle::Cast(funcVal); if (transFunc->GetFunctionKind() != ecmascript::FunctionKind::CONCURRENT_FUNCTION) { return false; } ecmascript::JSThread *thread = vm->GetJSThread(); JSHandle method(thread, transFunc->GetMethod()); const JSPandaFile *jsPandaFile = method->GetJSPandaFile(); if (jsPandaFile == nullptr) { return false; } ecmascript::CString moduleName = jsPandaFile->GetJSPandaFileDesc(); ecmascript::CString recordName = method->GetRecordName(); // for debugger, to notify the script loaded and parsed which the concurrent function is in auto *notificationMgr = vm->GetJsDebuggerManager()->GetNotificationManager(); notificationMgr->LoadModuleEvent(moduleName, recordName); bool isModule = jsPandaFile->IsModule(thread, recordName); if (isModule) { ecmascript::ModuleManager *moduleManager = vm->GetModuleManager(); JSHandle moduleRecord; if (jsPandaFile->IsBundlePack()) { moduleRecord = moduleManager->HostResolveImportedModule(moduleName); } else { moduleRecord = moduleManager->HostResolveImportedModuleWithMerge(moduleName, recordName); if (ecmascript::AnFileDataManager::GetInstance()->IsEnable()) { vm->GetAOTFileManager()->LoadAiFile(jsPandaFile); } } ecmascript::SourceTextModule::Instantiate(thread, moduleRecord); if (thread->HasPendingException()) { auto exception = thread->GetException(); vm->HandleUncaughtException(exception.GetTaggedObject()); return false; } JSHandle module = JSHandle::Cast(moduleRecord); module->SetStatus(ecmascript::ModuleStatus::INSTANTIATED); ecmascript::SourceTextModule::EvaluateForConcurrent(thread, module); transFunc->SetModule(thread, module); return true; } return false; } } // namespace panda