/* * Copyright (c) 2021-2022 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 "ecmascript/debugger/debugger_api.h" #include "ecmascript/base/number_helper.h" #include "ecmascript/debugger/js_debugger.h" #include "ecmascript/ecma_macros.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/interpreter/slow_runtime_stub.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/jspandafile/js_pandafile_executor.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_handle.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/method.h" #include "ecmascript/module/js_module_manager.h" #include "ecmascript/module/js_module_source_text.h" #include "ecmascript/napi/jsnapi_helper.h" #include "ecmascript/tagged_array.h" #include "ecmascript/tagged_dictionary.h" #include "ecmascript/tagged_hash_array.h" #include "ecmascript/tagged_tree.h" #include "ecmascript/tagged_queue.h" #include "ecmascript/js_api/js_api_hashmap.h" #include "ecmascript/js_api/js_api_hashset.h" #include "ecmascript/js_api/js_api_tree_map.h" #include "ecmascript/js_api/js_api_tree_set.h" #include "ecmascript/js_api/js_api_lightweightmap.h" #include "ecmascript/js_api/js_api_lightweightset.h" #include "ecmascript/jobs/micro_job_queue.h" #include "ecmascript/frames.h" namespace panda::ecmascript::tooling { using panda::ecmascript::base::ALLOW_BINARY; using panda::ecmascript::base::ALLOW_HEX; using panda::ecmascript::base::ALLOW_OCTAL; using panda::ecmascript::base::NumberHelper; using ecmascript::JSAPIArrayList; using ecmascript::JSAPIDeque; using ecmascript::JSAPIHashMap; using ecmascript::JSAPIHashSet; using ecmascript::JSAPILightWeightMap; using ecmascript::JSAPILightWeightSet; using ecmascript::JSAPIList; using ecmascript::JSAPILinkedList; using ecmascript::JSAPIPlainArray; using ecmascript::JSAPIStack; using ecmascript::JSAPIQueue; using ecmascript::JSAPITreeSet; using ecmascript::JSAPITreeMap; using ecmascript::JSAPIVector; using ecmascript::LinkedNode; using ecmascript::TaggedHashArray; using ecmascript::TaggedNode; using ecmascript::RBTreeNode; using ecmascript::TaggedTreeSet; using ecmascript::TaggedTreeMap; using ecmascript::TaggedQueue; // FrameHandler uint32_t DebuggerApi::GetStackDepth(const EcmaVM *ecmaVm) { uint32_t count = 0; FrameHandler frameHandler(ecmaVm->GetJSThread()); for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) { if (frameHandler.IsEntryFrame() || frameHandler.IsBuiltinFrame()) { continue; } ++count; } return count; } std::shared_ptr<FrameHandler> DebuggerApi::NewFrameHandler(const EcmaVM *ecmaVm) { return std::make_shared<FrameHandler>(ecmaVm->GetJSThread()); } bool DebuggerApi::StackWalker(const EcmaVM *ecmaVm, std::function<StackState(const FrameHandler *)> func) { FrameHandler frameHandler(ecmaVm->GetJSThread()); for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) { if (frameHandler.IsEntryFrame() || frameHandler.IsBuiltinFrame()) { continue; } StackState state = func(&frameHandler); if (state == StackState::CONTINUE) { continue; } if (state == StackState::FAILED) { return false; } return true; } return true; } uint32_t DebuggerApi::GetStackDepthOverBuiltin(const EcmaVM *ecmaVm) { uint32_t count = 0; FrameHandler frameHandler(ecmaVm->GetJSThread()); for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) { if (frameHandler.IsEntryFrame()) { continue; } if (frameHandler.IsBuiltinFrame()) { break; } ++count; } return count; } uint32_t DebuggerApi::GetBytecodeOffset(const EcmaVM *ecmaVm) { return FrameHandler(ecmaVm->GetJSThread()).GetBytecodeOffset(); } std::unique_ptr<PtMethod> DebuggerApi::GetMethod(const EcmaVM *ecmaVm) { FrameHandler frameHandler(ecmaVm->GetJSThread()); Method* method = frameHandler.GetMethod(); std::unique_ptr<PtMethod> ptMethod = std::make_unique<PtMethod>( method->GetJSPandaFile(), method->GetMethodId(), method->IsNativeWithCallField()); return ptMethod; } void DebuggerApi::SetVRegValue(FrameHandler *frameHandler, size_t index, Local<JSValueRef> value) { return frameHandler->SetVRegValue(index, JSNApiHelper::ToJSTaggedValue(*value)); } uint32_t DebuggerApi::GetBytecodeOffset(const FrameHandler *frameHandler) { return frameHandler->GetBytecodeOffset(); } Method *DebuggerApi::GetMethod(const FrameHandler *frameHandler) { return frameHandler->GetMethod(); } bool DebuggerApi::IsNativeMethod(const EcmaVM *ecmaVm) { FrameHandler frameHandler(ecmaVm->GetJSThread()); return DebuggerApi::IsNativeMethod(&frameHandler); } bool DebuggerApi::IsNativeMethod(const FrameHandler *frameHandler) { if (!frameHandler->HasFrame()) { return false; } Method* method = frameHandler->GetMethod(); return method->IsNativeWithCallField(); } JSPandaFile *DebuggerApi::GetJSPandaFile(const EcmaVM *ecmaVm) { Method *method = FrameHandler(ecmaVm->GetJSThread()).GetMethod(); return const_cast<JSPandaFile *>(method->GetJSPandaFile()); } JSTaggedValue DebuggerApi::GetEnv(const FrameHandler *frameHandler) { return frameHandler->GetEnv(); } JSTaggedType *DebuggerApi::GetSp(const FrameHandler *frameHandler) { return frameHandler->GetSp(); } int32_t DebuggerApi::GetVregIndex(const FrameHandler *frameHandler, std::string_view name) { Method *method = DebuggerApi::GetMethod(frameHandler); if (method->IsNativeWithCallField()) { LOG_DEBUGGER(ERROR) << "GetVregIndex: native frame not support"; return -1; } DebugInfoExtractor *extractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile()); if (extractor == nullptr) { LOG_DEBUGGER(ERROR) << "GetVregIndex: extractor is null"; return -1; } uint32_t currentOffset = frameHandler->GetBytecodeOffset(); int32_t regNumber = -1; uint32_t startOffset = 0; uint32_t endOffset = UINT32_MAX; auto table = extractor->GetLocalVariableTable(method->GetMethodId()); for (auto iter = table.begin(); iter != table.end(); iter++) { // if currentOffset not in variable's scope, skip it if (iter->name == name.data() && currentOffset >= iter->startOffset && currentOffset <= iter->endOffset) { // if there are multiple variables with the same name, get regNumber with the smallest scope if (iter->startOffset >= startOffset && iter->endOffset <= endOffset) { regNumber = iter->regNumber; startOffset = iter->startOffset; endOffset = iter->endOffset; } } } if (regNumber != -1) { return regNumber; } return -1; } Local<JSValueRef> DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm, const FrameHandler *frameHandler, size_t index) { auto value = frameHandler->GetVRegValue(index); JSHandle<JSTaggedValue> handledValue(ecmaVm->GetJSThread(), value); return JSNApiHelper::ToLocal<JSValueRef>(handledValue); } // JSThread Local<JSValueRef> DebuggerApi::GetAndClearException(const EcmaVM *ecmaVm) { auto exception = ecmaVm->GetJSThread()->GetException(); JSHandle<JSTaggedValue> handledException(ecmaVm->GetJSThread(), exception); ecmaVm->GetJSThread()->ClearException(); return JSNApiHelper::ToLocal<JSValueRef>(handledException); } void DebuggerApi::SetException(const EcmaVM *ecmaVm, Local<JSValueRef> exception) { ecmaVm->GetJSThread()->SetException(JSNApiHelper::ToJSTaggedValue(*exception)); } void DebuggerApi::ClearException(const EcmaVM *ecmaVm) { return ecmaVm->GetJSThread()->ClearException(); } // NumberHelper double DebuggerApi::StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix) { return NumberHelper::StringToDouble(start, end, radix, ALLOW_BINARY | ALLOW_HEX | ALLOW_OCTAL); } // JSDebugger JSDebugger *DebuggerApi::CreateJSDebugger(const EcmaVM *ecmaVm) { return new JSDebugger(ecmaVm); } void DebuggerApi::DestroyJSDebugger(JSDebugger *debugger) { delete debugger; } void DebuggerApi::RegisterHooks(JSDebugger *debugger, PtHooks *hooks) { debugger->RegisterHooks(hooks); } bool DebuggerApi::SetBreakpoint(JSDebugger *debugger, const JSPtLocation &location, Local<FunctionRef> condFuncRef) { return debugger->SetBreakpoint(location, condFuncRef); } bool DebuggerApi::RemoveBreakpoint(JSDebugger *debugger, const JSPtLocation &location) { return debugger->RemoveBreakpoint(location); } void DebuggerApi::RemoveAllBreakpoints(JSDebugger *debugger) { return debugger->RemoveAllBreakpoints(); } void DebuggerApi::SetSingleStepStatus(JSDebugger *debugger, bool status) { return debugger->SetSingleStepStatus(status); } bool DebuggerApi::GetSingleStepStatus(JSDebugger *debugger) { return debugger->GetSingleStepStatus(); } int32_t DebuggerApi::GetObjectHash(const EcmaVM *ecmaVM, const JSHandle<JSTaggedValue> &tagged) { if (!tagged->IsECMAObject()) { return 0; } bool hasHash = ECMAObject::Cast(tagged->GetTaggedObject())->HasHash(); if (!hasHash) { int32_t hash = base::RandomGenerator::GenerateIdentityHash(); auto ecmaObj = ECMAObject::Cast(tagged->GetTaggedObject()); JSHandle<ECMAObject> ecmaObjHandle(ecmaVM->GetJSThread(), ecmaObj); ECMAObject::SetHash(ecmaVM->GetJSThread(), hash, ecmaObjHandle); return hash; } else { return ECMAObject::Cast(tagged->GetTaggedObject())->GetHash(); } } // ScopeInfo Local<JSValueRef> DebuggerApi::GetProperties(const EcmaVM *ecmaVm, const FrameHandler *frameHandler, int32_t level, uint32_t slot) { JSTaggedValue env = frameHandler->GetEnv(); for (int i = 0; i < level; i++) { JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); ASSERT(!taggedParentEnv.IsUndefined()); env = taggedParentEnv; } JSTaggedValue value = LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot); JSHandle<JSTaggedValue> handledValue(ecmaVm->GetJSThread(), value); return JSNApiHelper::ToLocal<JSValueRef>(handledValue); } void DebuggerApi::SetProperties(const EcmaVM *ecmaVm, const FrameHandler *frameHandler, int32_t level, uint32_t slot, Local<JSValueRef> value) { JSTaggedValue env = frameHandler->GetEnv(); for (int i = 0; i < level; i++) { JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); ASSERT(!taggedParentEnv.IsUndefined()); env = taggedParentEnv; } JSTaggedValue target = JSNApiHelper::ToJSHandle(value).GetTaggedValue(); LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(ecmaVm->GetJSThread(), slot, target); } std::pair<int32_t, uint32_t> DebuggerApi::GetLevelSlot(const FrameHandler *frameHandler, std::string_view name) { int32_t level = 0; uint32_t slot = 0; JSTaggedValue curEnv = frameHandler->GetEnv(); for (; curEnv.IsTaggedArray(); curEnv = LexicalEnv::Cast(curEnv.GetTaggedObject())->GetParentEnv(), level++) { LexicalEnv *lexicalEnv = LexicalEnv::Cast(curEnv.GetTaggedObject()); if (lexicalEnv->GetScopeInfo().IsHole()) { continue; } auto result = JSNativePointer::Cast(lexicalEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer(); ScopeDebugInfo *scopeDebugInfo = reinterpret_cast<ScopeDebugInfo *>(result); auto iter = scopeDebugInfo->scopeInfo.find(name.data()); if (iter == scopeDebugInfo->scopeInfo.end()) { continue; } slot = iter->second; return std::make_pair(level, slot); } return std::make_pair(-1, 0); } Local<JSValueRef> DebuggerApi::GetGlobalValue(const EcmaVM *ecmaVm, Local<StringRef> name) { JSTaggedValue result; JSTaggedValue globalObj = ecmaVm->GetGlobalEnv()->GetGlobalObject(); JSThread *thread = ecmaVm->GetJSThread(); JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name); JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key); if (!globalRec.IsUndefined()) { ASSERT(globalRec.IsPropertyBox()); result = PropertyBox::Cast(globalRec.GetTaggedObject())->GetValue(); return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, result)); } JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key); if (!globalVar.IsHole()) { return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, globalVar)); } else { result = SlowRuntimeStub::TryLdGlobalByNameFromGlobalProto(thread, globalObj, key); return JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, result)); } return Local<JSValueRef>(); } bool DebuggerApi::SetGlobalValue(const EcmaVM *ecmaVm, Local<StringRef> name, Local<JSValueRef> value) { JSTaggedValue result; JSTaggedValue globalObj = ecmaVm->GetGlobalEnv()->GetGlobalObject(); JSThread *thread = ecmaVm->GetJSThread(); JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name); JSTaggedValue newVal = JSNApiHelper::ToJSTaggedValue(*value); JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key); if (!globalRec.IsUndefined()) { result = SlowRuntimeStub::TryUpdateGlobalRecord(thread, key, newVal); return !result.IsException(); } JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key); if (!globalVar.IsHole()) { result = SlowRuntimeStub::StGlobalVar(thread, key, newVal); return !result.IsException(); } return false; } JSTaggedValue DebuggerApi::GetCurrentModule(const EcmaVM *ecmaVm) { JSThread *thread = ecmaVm->GetJSThread(); FrameHandler frameHandler(thread); for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) { if (frameHandler.IsEntryFrame()) { continue; } Method *method = frameHandler.GetMethod(); // Skip builtins method if (method->IsNativeWithCallField()) { continue; } JSTaggedValue module = method->GetModule(); if (module.IsUndefined()) { continue; } return module; } UNREACHABLE(); } JSHandle<JSTaggedValue> DebuggerApi::GetImportModule(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule, std::string &name) { JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<JSTaggedValue> importModule(thread, thread->GlobalConstants()->GetUndefined()); if (!currentModule->IsSourceTextModule()) { return importModule; } JSTaggedValue importEntries = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetImportEntries(); if (importEntries.IsUndefined()) { return importModule; } JSHandle<TaggedArray> importArray(thread, TaggedArray::Cast(importEntries.GetTaggedObject())); size_t importEntriesLen = importArray->GetLength(); JSHandle<JSTaggedValue> starString = thread->GlobalConstants()->GetHandledStarString(); JSMutableHandle<ImportEntry> ee(thread, thread->GlobalConstants()->GetUndefined()); JSMutableHandle<TaggedArray> environment(thread, thread->GlobalConstants()->GetUndefined()); for (size_t idx = 0; idx < importEntriesLen; idx++) { ee.Update(importArray->Get(idx)); JSTaggedValue localName = ee->GetLocalName(); JSTaggedValue importName = ee->GetImportName(); // Skip 'import * as name from xxx' if (localName.IsString() && !JSTaggedValue::SameValue(importName, starString.GetTaggedValue())) { std::string varName = EcmaStringAccessor(localName).ToStdString(); if (varName != name) { continue; } JSTaggedValue moduleEnvironment = SourceTextModule::Cast( currentModule->GetTaggedObject())->GetEnvironment(); environment.Update(moduleEnvironment); JSTaggedValue resolvedBinding = environment->Get(idx); ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject()); importModule.Update(binding->GetModule()); name = EcmaStringAccessor(importName).ToStdString(); return importModule; } } return importModule; } int32_t DebuggerApi::GetModuleVariableIndex(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule, std::string &name) { if (!currentModule->IsSourceTextModule()) { return -1; } JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary(); if (dictionary.IsUndefined()) { return -1; } JSThread *thread = ecmaVm->GetJSThread(); if (dictionary.IsTaggedArray()) { JSTaggedValue localExportEntries = SourceTextModule::Cast( currentModule->GetTaggedObject())->GetLocalExportEntries(); ASSERT(localExportEntries.IsTaggedArray()); JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject())); uint32_t exportEntriesLen = localExportArray->GetLength(); JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined()); for (uint32_t idx = 0; idx < exportEntriesLen; idx++) { ee.Update(localExportArray->Get(idx)); JSTaggedValue localKey = ee->GetLocalName(); JSTaggedValue exportKey = ee->GetExportName(); if (localKey.IsString() && exportKey.IsString()) { std::string localName = EcmaStringAccessor(localKey).ToStdString(); std::string exportName = EcmaStringAccessor(exportKey).ToStdString(); if (localName == name || exportName == name) { return idx; } } } } return -1; } int32_t DebuggerApi::GetRequestModuleIndex(const EcmaVM *ecmaVm, JSTaggedValue moduleRequest, const JSHandle<JSTaggedValue> ¤tModule) { if (!currentModule->IsSourceTextModule()) { return -1; } JSThread *thread = ecmaVm->GetJSThread(); JSHandle<SourceTextModule> module(thread, SourceTextModule::Cast(currentModule->GetTaggedObject())); JSHandle<JSTaggedValue> required(thread, moduleRequest); JSHandle<TaggedArray> requestedModules(thread, module->GetRequestedModules()); uint32_t requestedModulesLen = requestedModules->GetLength(); for (uint32_t idx = 0; idx < requestedModulesLen; idx++) { JSTaggedValue requestModule = requestedModules->Get(idx); if (JSTaggedValue::SameValue(required.GetTaggedValue(), requestModule)) { return idx; } } LOG_ECMA(FATAL) << "this branch is unreachable"; return -1; } Local<JSValueRef> DebuggerApi::GetExportVariableValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule, std::string &name) { Local<JSValueRef> result; if (!currentModule->IsSourceTextModule()) { return result; } int32_t index = GetModuleVariableIndex(ecmaVm, currentModule, name); if (index == -1) { return result; } JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary(); if (dictionary.IsUndefined()) { return result; } JSThread *thread = ecmaVm->GetJSThread(); if (dictionary.IsTaggedArray()) { TaggedArray *array = TaggedArray::Cast(dictionary.GetTaggedObject()); JSTaggedValue moduleValue = array->Get(index); result = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, moduleValue)); return result; } return result; } bool DebuggerApi::SetExportVariableValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule, std::string &name, Local<JSValueRef> value) { if (!currentModule->IsSourceTextModule()) { return false; } int32_t index = GetModuleVariableIndex(ecmaVm, currentModule, name); if (index == -1) { return false; } JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary(); if (dictionary.IsUndefined()) { return false; } JSThread *thread = ecmaVm->GetJSThread(); JSTaggedValue curValue = JSNApiHelper::ToJSTaggedValue(*value); if (dictionary.IsTaggedArray()) { TaggedArray *array = TaggedArray::Cast(dictionary.GetTaggedObject()); array->Set(thread, index, curValue); return true; } return false; } Local<JSValueRef> DebuggerApi::GetModuleValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule, std::string &name) { Local<JSValueRef> result; if (!currentModule->IsSourceTextModule()) { return result; } // Get variable from local export result = GetExportVariableValue(ecmaVm, currentModule, name); if (!result.IsEmpty()) { return result; } // Get variable from import module JSHandle<JSTaggedValue> importModule = GetImportModule(ecmaVm, currentModule, name); result = GetExportVariableValue(ecmaVm, importModule, name); return result; } bool DebuggerApi::SetModuleValue(const EcmaVM *ecmaVm, const JSHandle<JSTaggedValue> ¤tModule, std::string &name, Local<JSValueRef> value) { bool result; if (!currentModule->IsSourceTextModule()) { return false; } // Set local export variable result = SetExportVariableValue(ecmaVm, currentModule, name, value); if (result == true) { return result; } // Set import module variable JSHandle<JSTaggedValue> importModule = GetImportModule(ecmaVm, currentModule, name); result = SetExportVariableValue(ecmaVm, importModule, name, value); if (result == true) { return result; } return false; } void DebuggerApi::InitializeExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj, const JSHandle<JSTaggedValue> ¤tModule) { if (!currentModule->IsSourceTextModule()) { return; } JSTaggedValue localExportEntries = SourceTextModule::Cast( currentModule->GetTaggedObject())->GetLocalExportEntries(); if (localExportEntries.IsUndefined()) { return; } JSThread *thread = ecmaVm->GetJSThread(); JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject())); uint32_t exportEntriesLen = localExportArray->GetLength(); JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined()); JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined()); JSMutableHandle<JSTaggedValue> value(thread, thread->GlobalConstants()->GetUndefined()); JSTaggedValue moduleValue = JSTaggedValue::Undefined(); for (uint32_t idx = 0; idx < exportEntriesLen; idx++) { ee.Update(localExportArray->Get(idx)); JSTaggedValue key = ee->GetLocalName(); name.Update(key); value.Update(moduleValue); if (key.IsString()) { Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name); Local<JSValueRef> variableValue = JSNApiHelper::ToLocal<JSValueRef>(value); PropertyAttribute descriptor(variableValue, true, true, true); moduleObj->DefineProperty(ecmaVm, variableName, descriptor); } } } void DebuggerApi::GetLocalExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj, const JSHandle<JSTaggedValue> ¤tModule, bool isImportStar) { if (!currentModule->IsSourceTextModule()) { return; } JSTaggedValue dictionary = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetNameDictionary(); if (dictionary.IsUndefined()) { InitializeExportVariables(ecmaVm, moduleObj, currentModule); return; } JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined()); JSMutableHandle<JSTaggedValue> value(thread, thread->GlobalConstants()->GetUndefined()); if (dictionary.IsTaggedArray()) { JSTaggedValue localExportEntries = SourceTextModule::Cast( currentModule->GetTaggedObject())->GetLocalExportEntries(); ASSERT(localExportEntries.IsTaggedArray()); JSHandle<TaggedArray> localExportArray(thread, TaggedArray::Cast(localExportEntries.GetTaggedObject())); uint32_t exportEntriesLen = localExportArray->GetLength(); JSHandle<TaggedArray> dict(thread, TaggedArray::Cast(dictionary.GetTaggedObject())); uint32_t valueLen = dict->GetLength(); if (exportEntriesLen != valueLen) { LOG_FULL(FATAL) << "Key does not match value"; } JSMutableHandle<LocalExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined()); for (uint32_t idx = 0; idx < exportEntriesLen; idx++) { ee.Update(localExportArray->Get(idx)); JSTaggedValue key; if (isImportStar) { key = ee->GetExportName(); } else { key = ee->GetLocalName(); } name.Update(key); JSTaggedValue moduleValue = dict->Get(idx); if (moduleValue.IsHole()) { moduleValue = JSTaggedValue::Undefined(); } value.Update(moduleValue); if (key.IsString()) { Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name); Local<JSValueRef> variableValue = JSNApiHelper::ToLocal<JSValueRef>(value); PropertyAttribute descriptor(variableValue, true, true, true); moduleObj->DefineProperty(ecmaVm, variableName, descriptor); } } } } void DebuggerApi::GetIndirectExportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj, const JSHandle<JSTaggedValue> ¤tModule) { if (!currentModule->IsSourceTextModule()) { return; } JSTaggedValue indirectExportEntries = SourceTextModule::Cast( currentModule->GetTaggedObject())->GetIndirectExportEntries(); if (indirectExportEntries.IsUndefined()) { return; } ASSERT(indirectExportEntries.IsTaggedArray()); JSThread *thread = ecmaVm->GetJSThread(); JSHandle<TaggedArray> indirectExportArray(thread, TaggedArray::Cast(indirectExportEntries.GetTaggedObject())); uint32_t indirectExportEntriesLen = indirectExportArray->GetLength(); JSMutableHandle<IndirectExportEntry> ee(thread, thread->GlobalConstants()->GetUndefined()); JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined()); for (uint32_t idx = 0; idx < indirectExportEntriesLen; idx++) { ee.Update(indirectExportArray->Get(idx)); JSTaggedValue key = ee->GetImportName(); name.Update(key); if (key.IsString()) { Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name); JSHandle<JSTaggedValue> moduleRequest(thread, ee->GetModuleRequest()); JSHandle<JSTaggedValue> importModule; JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(currentModule); JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName(); if (moduleRecordName.IsUndefined()) { importModule = SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); } else { importModule = SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest); RETURN_IF_ABRUPT_COMPLETION(thread); } std::string importName = EcmaStringAccessor(ee->GetImportName()).ToStdString(); Local<JSValueRef> value = GetModuleValue(ecmaVm, importModule, importName); PropertyAttribute descriptor(value, true, true, true); moduleObj->DefineProperty(ecmaVm, variableName, descriptor); } } } void DebuggerApi::GetImportVariables(const EcmaVM *ecmaVm, Local<ObjectRef> &moduleObj, const JSHandle<JSTaggedValue> ¤tModule) { if (!currentModule->IsSourceTextModule()) { return; } JSTaggedValue importEntries = SourceTextModule::Cast(currentModule->GetTaggedObject())->GetImportEntries(); if (importEntries.IsUndefined()) { return; } JSThread *thread = ecmaVm->GetJSThread(); JSHandle<TaggedArray> importArray(thread, TaggedArray::Cast(importEntries.GetTaggedObject())); uint32_t importEntriesLen = importArray->GetLength(); JSHandle<JSTaggedValue> starString = thread->GlobalConstants()->GetHandledStarString(); JSMutableHandle<ImportEntry> ee(thread, thread->GlobalConstants()->GetUndefined()); JSMutableHandle<JSTaggedValue> name(thread, thread->GlobalConstants()->GetUndefined()); for (uint32_t idx = 0; idx < importEntriesLen; idx++) { ee.Update(importArray->Get(idx)); JSTaggedValue key = ee->GetImportName(); JSTaggedValue localName = ee->GetLocalName(); name.Update(localName); if (JSTaggedValue::SameValue(key, starString.GetTaggedValue())) { JSHandle<JSTaggedValue> moduleRequest(thread, ee->GetModuleRequest()); JSHandle<JSTaggedValue> importModule; JSHandle<SourceTextModule> module = JSHandle<SourceTextModule>::Cast(currentModule); JSTaggedValue moduleRecordName = module->GetEcmaModuleRecordName(); if (moduleRecordName.IsUndefined()) { importModule = SourceTextModule::HostResolveImportedModule(thread, module, moduleRequest); } else { importModule = SourceTextModule::HostResolveImportedModuleWithMerge(thread, module, moduleRequest); RETURN_IF_ABRUPT_COMPLETION(thread); } Local<ObjectRef> importModuleObj = ObjectRef::New(ecmaVm); GetLocalExportVariables(ecmaVm, importModuleObj, importModule, true); Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name); PropertyAttribute descriptor(static_cast<Local<JSValueRef>>(importModuleObj), true, true, true); moduleObj->DefineProperty(ecmaVm, variableName, descriptor); continue; } JSTaggedValue moduleValue = thread->GetCurrentEcmaContext()->GetModuleManager()->GetModuleValueOutter(idx, currentModule); Local<JSValueRef> value = JSNApiHelper::ToLocal<JSValueRef>(JSHandle<JSTaggedValue>(thread, moduleValue)); Local<JSValueRef> variableName = JSNApiHelper::ToLocal<JSValueRef>(name); PropertyAttribute descriptor(value, true, true, true); moduleObj->DefineProperty(ecmaVm, variableName, descriptor); } } void DebuggerApi::HandleUncaughtException(const EcmaVM *ecmaVm, std::string &message) { JSThread *thread = ecmaVm->GetJSThread(); [[maybe_unused]] EcmaHandleScope handleScope(thread); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle<JSTaggedValue> exHandle(thread, thread->GetException()); thread->ClearException(); if (exHandle->IsJSError()) { JSHandle<JSTaggedValue> nameKey = globalConst->GetHandledNameString(); JSHandle<EcmaString> name(JSObject::GetProperty(thread, exHandle, nameKey).GetValue()); JSHandle<JSTaggedValue> msgKey = globalConst->GetHandledMessageString(); JSHandle<EcmaString> msg(JSObject::GetProperty(thread, exHandle, msgKey).GetValue()); message = ConvertToString(*name) + ": " + ConvertToString(*msg); } else { JSHandle<EcmaString> ecmaStr = JSTaggedValue::ToString(thread, exHandle); message = ConvertToString(*ecmaStr); } } Local<FunctionRef> DebuggerApi::GenerateFuncFromBuffer(const EcmaVM *ecmaVm, const void *buffer, size_t size, std::string_view entryPoint) { JSPandaFileManager *mgr = JSPandaFileManager::GetInstance(); std::shared_ptr<JSPandaFile> jsPandaFile = mgr->LoadJSPandaFile(ecmaVm->GetJSThread(), "", entryPoint, buffer, size); if (jsPandaFile == nullptr) { return JSValueRef::Undefined(ecmaVm); } JSHandle<Program> program = mgr->GenerateProgram(const_cast<EcmaVM *>(ecmaVm), jsPandaFile.get(), entryPoint); JSTaggedValue func = program->GetMainFunction(); return JSNApiHelper::ToLocal<FunctionRef>(JSHandle<JSTaggedValue>(ecmaVm->GetJSThread(), func)); } Local<JSValueRef> DebuggerApi::EvaluateViaFuncCall(EcmaVM *ecmaVm, Local<FunctionRef> funcRef, std::shared_ptr<FrameHandler> &frameHandler) { JSNApi::EnableUserUncaughtErrorHandler(ecmaVm); JsDebuggerManager *mgr = ecmaVm->GetJsDebuggerManager(); bool prevDebugMode = mgr->IsDebugMode(); mgr->SetEvalFrameHandler(frameHandler); mgr->SetDebugMode(false); // in order to catch exception ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub(); std::vector<Local<JSValueRef>> args; auto result = funcRef->Call(ecmaVm, JSValueRef::Undefined(ecmaVm), args.data(), args.size()); mgr->SetDebugMode(prevDebugMode); ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub(); mgr->SetEvalFrameHandler(nullptr); return result; } Local<JSValueRef> DebuggerApi::CallFunctionOnCall(EcmaVM *ecmaVm, Local<FunctionRef> funcRef, std::shared_ptr<FrameHandler> &frameHandler) { JSNApi::EnableUserUncaughtErrorHandler(ecmaVm); JsDebuggerManager *mgr = ecmaVm->GetJsDebuggerManager(); bool prevDebugMode = mgr->IsDebugMode(); mgr->SetEvalFrameHandler(frameHandler); mgr->SetDebugMode(false); ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub(); std::vector<Local<JSValueRef>> args; auto result = funcRef->Call(ecmaVm, JSValueRef::Undefined(ecmaVm), args.data(), args.size()); mgr->SetDebugMode(prevDebugMode); ecmaVm->GetJSThread()->CheckSwitchDebuggerBCStub(); mgr->SetEvalFrameHandler(nullptr); return result; } bool DebuggerApi::IsExceptionCaught(const EcmaVM *ecmaVm) { FrameHandler frameHandler(ecmaVm->GetJSThread()); for (; frameHandler.HasFrame(); frameHandler.PrevJSFrame()) { if (frameHandler.IsEntryFrame()) { return false; } auto method = frameHandler.GetMethod(); if (method->FindCatchBlock(frameHandler.GetBytecodeOffset() != INVALID_INDEX)) { return true; } } return false; } std::vector<DebugInfoExtractor *> DebuggerApi::GetPatchExtractors(const EcmaVM *ecmaVm, const std::string &url) { const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager(); return hotReloadManager->GetPatchExtractors(url); } const JSPandaFile *DebuggerApi::GetBaseJSPandaFile(const EcmaVM *ecmaVm, const JSPandaFile *jsPandaFile) { const auto *hotReloadManager = ecmaVm->GetJsDebuggerManager()->GetHotReloadManager(); return hotReloadManager->GetBaseJSPandaFile(jsPandaFile); } std::vector<void *> DebuggerApi::GetNativePointer(const EcmaVM *ecmaVm) { void *native = nullptr; std::vector<void *> nativePointer; JSThread *thread = ecmaVm->GetJSThread(); JSTaggedType *current = const_cast<JSTaggedType *>(thread->GetCurrentFrame()); FrameIterator it(current, thread); for (; !it.Done(); it.Advance<GCVisitedFlag::HYBRID_STACK>()) { if (!it.IsJSFrame()) { continue; } auto method = it.CheckAndGetMethod(); if (method == nullptr) { continue; } if (method->IsNativeWithCallField()) { JSTaggedValue function = it.GetFunction(); JSHandle<JSTaggedValue> extraInfoValue( thread, JSFunction::Cast(function.GetTaggedObject())->GetFunctionExtraInfo()); auto cb = ecmaVm->GetNativePtrGetter(); if (extraInfoValue->IsJSNativePointer() && cb != nullptr) { JSHandle<JSNativePointer> extraInfo(extraInfoValue); native = cb(reinterpret_cast<void *>(extraInfo->GetData())); nativePointer.push_back(native); } } else { nativePointer.push_back(nullptr); // to tell IDE this frame don't hava nativePointer } } return nativePointer; } uint32_t DebuggerApi::GetContainerLength(const EcmaVM *ecmaVm, Local<JSValueRef> value) { uint32_t length = Local<ArrayRef>(value)->Length(ecmaVm); return length; } void DebuggerApi::AddInternalProperties(const EcmaVM *ecmaVm, Local<ObjectRef> object, ArkInternalValueType type, Global<MapRef> internalObjects) { if (internalObjects.IsEmpty()) { return; } internalObjects->Set(ecmaVm, object, NumberRef::New(ecmaVm, static_cast<int32_t>(type))); } Local<JSValueRef> DebuggerApi::GetArrayListValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIArrayList> arrayList(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(arrayList->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); uint32_t index = 0; while (index < size) { currentValue.Update(arrayList->Get(thread, index)); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetDequeValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIDeque> deque(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(deque->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); uint32_t index = 0; while (index < size) { currentValue.Update(deque->Get(index)); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetHashMapValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIHashMap> hashMap(JSNApiHelper::ToJSHandle(value)); JSThread *thread = ecmaVm->GetJSThread(); JSHandle<TaggedHashArray> table(thread, hashMap->GetTable()); uint32_t length = table->GetLength(); uint32_t size = static_cast<uint32_t>(hashMap->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSMutableHandle<TaggedQueue> queue(thread, factory->NewTaggedQueue(0)); JSMutableHandle<TaggedNode> node(thread, JSTaggedValue::Undefined()); JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined()); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); Local<JSValueRef> jsKey = StringRef::NewFromUtf8(ecmaVm, "key"); Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value"); uint32_t pos = 0; uint32_t index = 0; while (index < length) { node.Update(TaggedHashArray::GetCurrentNode(thread, queue, table, index)); if (!node.GetTaggedValue().IsHole()) { currentKey.Update(node->GetKey()); currentValue.Update(node->GetValue()); Local<ObjectRef> objRef = ObjectRef::New(ecmaVm); objRef->Set(ecmaVm, jsKey, JSNApiHelper::ToLocal<JSValueRef>(currentKey)); objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects); ArrayRef::SetValueAt(ecmaVm, jsValueRef, pos++, objRef); } } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetHashSetValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIHashSet> hashSet(JSNApiHelper::ToJSHandle(value)); JSThread *thread = ecmaVm->GetJSThread(); JSHandle<TaggedHashArray> table(thread, hashSet->GetTable()); uint32_t length = table->GetLength(); uint32_t size = static_cast<uint32_t>(hashSet->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSMutableHandle<TaggedQueue> queue(thread, factory->NewTaggedQueue(0)); JSMutableHandle<TaggedNode> node(thread, JSTaggedValue::Undefined()); JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined()); Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value"); uint32_t pos = 0; uint32_t index = 0; while (index < length) { node.Update(TaggedHashArray::GetCurrentNode(thread, queue, table, index)); if (!node.GetTaggedValue().IsHole()) { currentKey.Update(node->GetKey()); if (currentKey->IsECMAObject()) { Local<ObjectRef> objRef = ObjectRef::New(ecmaVm); objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentKey)); AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects); ArrayRef::SetValueAt(ecmaVm, jsValueRef, pos++, objRef); } else { ArrayRef::SetValueAt(ecmaVm, jsValueRef, pos++, JSNApiHelper::ToLocal<JSValueRef>(currentKey)); } } } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetLightWeightMapValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPILightWeightMap> lightweightMap(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(lightweightMap->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<TaggedArray> keys(thread, lightweightMap->GetKeys()); JSMutableHandle<TaggedArray> values(thread, lightweightMap->GetValues()); JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined()); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); Local<JSValueRef> jsKey = StringRef::NewFromUtf8(ecmaVm, "key"); Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value"); uint32_t index = 0; while (index < size) { currentKey.Update(keys->Get(index)); currentValue.Update(values->Get(index)); Local<ObjectRef> objRef = ObjectRef::New(ecmaVm); objRef->Set(ecmaVm, jsKey, JSNApiHelper::ToLocal<JSValueRef>(currentKey)); objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetLightWeightSetValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPILightWeightSet> lightWeightSet(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(lightWeightSet->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value"); uint32_t index = 0; while (index < size) { currentValue.Update(lightWeightSet->GetValueAt(index)); if (currentValue->IsECMAObject()) { Local<ObjectRef> objRef = ObjectRef::New(ecmaVm); objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef); } else { ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetLinkedListValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPILinkedList> linkedList(JSNApiHelper::ToJSHandle(value)); JSThread *thread = ecmaVm->GetJSThread(); JSHandle<TaggedDoubleList> doubleList(thread, linkedList->GetDoubleList()); uint32_t size = static_cast<uint32_t>(linkedList->Length()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); int valueNode = TaggedDoubleList::ELEMENTS_START_INDEX; uint32_t index = 0; while (index < size) { valueNode = doubleList->GetNextDataIndex(valueNode); currentValue.Update(doubleList->GetElement(valueNode)); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetListValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIList> list(JSNApiHelper::ToJSHandle(value)); JSThread *thread = ecmaVm->GetJSThread(); JSHandle<TaggedSingleList> singleList(thread, list->GetSingleList()); uint32_t size = static_cast<uint32_t>(list->Length()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); int valueNode = TaggedDoubleList::ELEMENTS_START_INDEX; uint32_t index = 0; while (index < size) { valueNode = singleList->GetNextDataIndex(valueNode); currentValue.Update(singleList->GetElement(valueNode)); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetPlainArrayValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIPlainArray> plainarray(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(plainarray->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSHandle<TaggedArray> keyArray(thread, plainarray->GetKeys()); JSHandle<TaggedArray> valueArray(thread, plainarray->GetValues()); JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined()); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); Local<JSValueRef> jsKey = StringRef::NewFromUtf8(ecmaVm, "key"); Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value"); uint32_t index = 0; while (index < size) { currentKey.Update(keyArray->Get(index)); currentValue.Update(valueArray->Get(index)); Local<ObjectRef> objRef = ObjectRef::New(ecmaVm); objRef->Set(ecmaVm, jsKey, JSNApiHelper::ToLocal<JSValueRef>(currentKey)); objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetQueueValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIQueue> queue(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(queue->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); uint32_t pos = 0; uint32_t index = 0; while (index < size) { currentValue.Update(queue->Get(thread, pos)); pos = queue->GetNextPosition(pos); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetStackValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIStack> stack(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(stack->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); uint32_t index = 0; while (index < size + 1) { currentValue.Update(stack->Get(index)); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetTreeMapValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPITreeMap> treeMap(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(treeMap->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<TaggedTreeMap> iteratedMap(thread, treeMap->GetTreeMap()); uint32_t elements = static_cast<uint32_t>(iteratedMap->NumberOfElements()); JSHandle<TaggedArray> entries = TaggedTreeMap::GetArrayFromMap(thread, iteratedMap); JSMutableHandle<JSTaggedValue> currentKey(thread, JSTaggedValue::Undefined()); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); Local<JSValueRef> jsKey = StringRef::NewFromUtf8(ecmaVm, "key"); Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value"); uint32_t index = 0; while (index < elements) { int entriesIndex = entries->Get(index).GetInt(); currentKey.Update(iteratedMap->GetKey(entriesIndex)); currentValue.Update(iteratedMap->GetValue(entriesIndex)); Local<ObjectRef> objRef = ObjectRef::New(ecmaVm); objRef->Set(ecmaVm, jsKey, JSNApiHelper::ToLocal<JSValueRef>(currentKey)); objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetTreeSetValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPITreeSet> treeSet(JSNApiHelper::ToJSHandle(value)); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<TaggedTreeSet> iteratedSet(thread, treeSet->GetTreeSet()); uint32_t elements = static_cast<uint32_t>(iteratedSet->NumberOfElements()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, elements); JSHandle<TaggedArray> entries = TaggedTreeSet::GetArrayFromSet(thread, iteratedSet); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); Local<JSValueRef> jsValue = StringRef::NewFromUtf8(ecmaVm, "value"); uint32_t index = 0; while (index < elements) { int entriesIndex = entries->Get(index).GetInt(); currentValue.Update(iteratedSet->GetKey(entriesIndex)); if (currentValue->IsECMAObject()) { Local<ObjectRef> objRef = ObjectRef::New(ecmaVm); objRef->Set(ecmaVm, jsValue, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); AddInternalProperties(ecmaVm, objRef, ArkInternalValueType::Entry, internalObjects); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, objRef); } else { ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } Local<JSValueRef> DebuggerApi::GetVectorValue(const EcmaVM *ecmaVm, Local<JSValueRef> value, Global<MapRef> internalObjects) { JSHandle<JSAPIVector> vector(JSNApiHelper::ToJSHandle(value)); uint32_t size = static_cast<uint32_t>(vector->GetSize()); Local<JSValueRef> jsValueRef = ArrayRef::New(ecmaVm, size); JSThread *thread = ecmaVm->GetJSThread(); JSMutableHandle<JSTaggedValue> currentValue(thread, JSTaggedValue::Undefined()); uint32_t index = 0; while (index < size) { currentValue.Update(vector->Get(thread, vector, index)); ArrayRef::SetValueAt(ecmaVm, jsValueRef, index++, JSNApiHelper::ToLocal<JSValueRef>(currentValue)); } AddInternalProperties(ecmaVm, jsValueRef, ArkInternalValueType::Entry, internalObjects); return jsValueRef; } bool DebuggerApi::CheckPromiseQueueSize(const EcmaVM *ecmaVm) { auto *debuggerMgr = ecmaVm->GetJsDebuggerManager(); uint32_t queueSizeEntry = debuggerMgr->GetPromiseQueueSizeRecordOfTopFrame(); JSThread *thread = ecmaVm->GetJSThread(); EcmaContext *context = thread->GetCurrentEcmaContext(); uint32_t queueSizeCurrent = job::MicroJobQueue::GetPromiseQueueSize(thread, context->GetMicroJobQueue()); return queueSizeEntry == queueSizeCurrent; } void DebuggerApi::DropLastFrame(const EcmaVM *ecmaVm) { auto *debuggerMgr = ecmaVm->GetJsDebuggerManager(); debuggerMgr->DropLastFrame(); } } // namespace panda::ecmascript::tooling