From 5119c012f8d0eee7b19281e8b12d4f4604e0d32e Mon Sep 17 00:00:00 2001 From: wengchangcheng Date: Thu, 24 Mar 2022 16:43:08 +0800 Subject: [PATCH] refactor debugger extractor 1. rename js_pt_extractor 2. move debug_info_extractor to js_runtime 3. use map to store MethodDebug info and LocalVariable info 4. refactor ScopeInfo extractor issue: https://gitee.com/openharmony/ark_js_runtime/issues/I5004N Signed-off-by: wengchangcheng Change-Id: Id64d718aa9360afd53398ee729714c859bd61768 --- BUILD.gn | 1 + ecmascript/base/error_helper.cpp | 8 +- ecmascript/dfx/cpu_profiler/cpu_profiler.cpp | 4 +- ecmascript/ecma_vm.cpp | 4 +- ecmascript/js_method.cpp | 12 +- ecmascript/js_method.h | 5 +- .../jspandafile/debug_info_extractor.cpp | 326 ++++++++++++++++++ ecmascript/jspandafile/debug_info_extractor.h | 87 +++++ ecmascript/jspandafile/js_pandafile.cpp | 9 - ecmascript/jspandafile/js_pandafile.h | 5 +- .../jspandafile/js_pandafile_manager.cpp | 19 +- ecmascript/jspandafile/js_pandafile_manager.h | 5 +- .../jspandafile/panda_file_translator.cpp | 41 ++- .../jspandafile/scope_info_extractor.cpp | 7 +- ecmascript/jspandafile/scope_info_extractor.h | 4 + ecmascript/lexical_env.h | 9 - ecmascript/tooling/BUILD.gn | 2 +- ecmascript/tooling/agent/js_backend.cpp | 69 ++-- ecmascript/tooling/agent/js_backend.h | 12 +- ecmascript/tooling/agent/js_pt_hooks.h | 2 +- ecmascript/tooling/interface/debugger_api.cpp | 28 +- ecmascript/tooling/interface/debugger_api.h | 4 +- ...t_js_extractor.cpp => js_pt_extractor.cpp} | 20 +- .../{pt_js_extractor.h => js_pt_extractor.h} | 20 +- ecmascript/tooling/protocol_handler.cpp | 1 + .../tooling/test/utils/test_extractor.cpp | 13 - .../tooling/test/utils/test_extractor.h | 10 +- ecmascript/tooling/test/utils/test_util.cpp | 32 -- ecmascript/tooling/test/utils/test_util.h | 6 - 29 files changed, 552 insertions(+), 213 deletions(-) create mode 100644 ecmascript/jspandafile/debug_info_extractor.cpp create mode 100644 ecmascript/jspandafile/debug_info_extractor.h rename ecmascript/tooling/{pt_js_extractor.cpp => js_pt_extractor.cpp} (84%) rename ecmascript/tooling/{pt_js_extractor.h => js_pt_extractor.h} (89%) diff --git a/BUILD.gn b/BUILD.gn index 4ac85f1be..e5872bad2 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -374,6 +374,7 @@ ecma_source = [ "ecmascript/js_api_stack.cpp", "ecmascript/js_api_stack_iterator.cpp", "ecmascript/jspandafile/class_info_extractor.cpp", + "ecmascript/jspandafile/debug_info_extractor.cpp", "ecmascript/jspandafile/ecma_class_linker_extension.cpp", "ecmascript/jspandafile/literal_data_extractor.cpp", "ecmascript/jspandafile/module_data_extractor.cpp", diff --git a/ecmascript/base/error_helper.cpp b/ecmascript/base/error_helper.cpp index 12748464a..cb173c322 100644 --- a/ecmascript/base/error_helper.cpp +++ b/ecmascript/base/error_helper.cpp @@ -26,10 +26,10 @@ #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/object_factory.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/js_pt_extractor.h" namespace panda::ecmascript::base { -using panda::tooling::ecmascript::PtJSExtractor; +using panda::tooling::ecmascript::JSPtExtractor; JSTaggedValue ErrorHelper::ErrorCommonToString(EcmaRuntimeCallInfo *argv, const ErrorType &errorType) { @@ -205,8 +205,8 @@ CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread) data += DecodeFunctionName(method->ParseFunctionName()); data.append(" ("); // source file - PtJSExtractor *debugExtractor = - JSPandaFileManager::GetInstance()->GetPtJSExtractor(method->GetJSPandaFile()); + JSPtExtractor *debugExtractor = + JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile()); const CString &sourceFile = debugExtractor->GetSourceFile(method->GetFileId()); if (sourceFile.empty()) { data.push_back('?'); diff --git a/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp b/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp index b39e6d40e..e5a68acdd 100644 --- a/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp +++ b/ecmascript/dfx/cpu_profiler/cpu_profiler.cpp @@ -206,8 +206,8 @@ void CpuProfiler::ParseMethodInfo(JSMethod *method, InterpretedFrameHandler fram codeEntry.functionName = functionName.c_str(); } // source file - tooling::ecmascript::PtJSExtractor *debugExtractor = - JSPandaFileManager::GetInstance()->GetPtJSExtractor(method->GetJSPandaFile()); + tooling::ecmascript::JSPtExtractor *debugExtractor = + JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile()); const CString &sourceFile = debugExtractor->GetSourceFile(method->GetFileId()); if (sourceFile.empty()) { codeEntry.url = ""; diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index a95a32aa3..9f4088d83 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -359,8 +359,8 @@ JSMethod *EcmaVM::GetMethodForNativeFunction(const void *func) uint32_t accessFlags = ACC_PUBLIC | ACC_STATIC | ACC_FINAL | ACC_NATIVE; uint32_t numArgs = 2; // function object and this - auto method = chunk_.New(nullptr, nullptr, panda_file::File::EntityId(0), panda_file::File::EntityId(0), - accessFlags, numArgs, nullptr); + auto method = chunk_.New(nullptr, panda_file::File::EntityId(0), panda_file::File::EntityId(0), + accessFlags, numArgs); method->SetNativePointer(const_cast(func)); method->SetNativeBit(true); diff --git a/ecmascript/js_method.cpp b/ecmascript/js_method.cpp index cc6ac2519..ab5bdb047 100644 --- a/ecmascript/js_method.cpp +++ b/ecmascript/js_method.cpp @@ -19,14 +19,14 @@ #include "libpandafile/method_data_accessor-inl.h" namespace panda::ecmascript { -JSMethod::JSMethod(Class *klass, const JSPandaFile *jsPandaFile, panda_file::File::EntityId fileId, +JSMethod::JSMethod(const JSPandaFile *jsPandaFile, panda_file::File::EntityId fileId, panda_file::File::EntityId codeId, uint32_t accessFlags, - uint32_t numArgs, const uint16_t *shorty) - : Method(klass, jsPandaFile != nullptr ? jsPandaFile->GetPandaFile() : nullptr, - fileId, codeId, accessFlags, numArgs, shorty) + uint32_t numArgs) + : Method(nullptr, jsPandaFile != nullptr ? jsPandaFile->GetPandaFile() : nullptr, + fileId, codeId, accessFlags, numArgs, nullptr) { - bytecodeArray_ = JSMethod::GetInstructions(); - bytecodeArraySize_ = JSMethod::GetCodeSize(); + bytecodeArray_ = GetInstructions(); + bytecodeArraySize_ = GetCodeSize(); jsPandaFile_ = jsPandaFile; } diff --git a/ecmascript/js_method.h b/ecmascript/js_method.h index 2ab9711d3..42f17c6a6 100644 --- a/ecmascript/js_method.h +++ b/ecmascript/js_method.h @@ -61,9 +61,8 @@ public: return static_cast(method); } - JSMethod(Class *klass, const JSPandaFile *jsPandaFile, panda_file::File::EntityId fileId, - panda_file::File::EntityId codeId, uint32_t accessFlags, - uint32_t numArgs, const uint16_t *shorty); + JSMethod(const JSPandaFile *jsPandaFile, panda_file::File::EntityId fileId, + panda_file::File::EntityId codeId, uint32_t accessFlags, uint32_t numArgs); JSMethod() = delete; ~JSMethod() = default; JSMethod(const JSMethod &) = delete; diff --git a/ecmascript/jspandafile/debug_info_extractor.cpp b/ecmascript/jspandafile/debug_info_extractor.cpp new file mode 100644 index 000000000..cf8a5961a --- /dev/null +++ b/ecmascript/jspandafile/debug_info_extractor.cpp @@ -0,0 +1,326 @@ +/* + * 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 "ecmascript/jspandafile/debug_info_extractor.h" + +#include "libpandabase/utils/utf.h" +#include "libpandafile/class_data_accessor-inl.h" +#include "libpandafile/debug_data_accessor-inl.h" +#include "libpandafile/line_program_state.h" + +namespace panda::ecmascript { +using panda::panda_file::ClassDataAccessor; +using panda::panda_file::DebugInfoDataAccessor; +using panda::panda_file::LineNumberProgramItem; +using panda::panda_file::LineProgramState; +using panda::panda_file::MethodDataAccessor; +using panda::panda_file::ProtoDataAccessor; + +static const char *GetStringFromConstantPool(const panda_file::File &pf, uint32_t offset) +{ + return utf::Mutf8AsCString(pf.GetStringData(panda_file::File::EntityId(offset)).data); +} + +DebugInfoExtractor::DebugInfoExtractor(const panda_file::File *pf) +{ + Extract(pf); +} + +class LineNumberProgramProcessor { +public: + LineNumberProgramProcessor(LineProgramState state, const uint8_t *program) : state_(state), program_(program) {} + + ~LineNumberProgramProcessor() = default; + + NO_COPY_SEMANTIC(LineNumberProgramProcessor); + NO_MOVE_SEMANTIC(LineNumberProgramProcessor); + + void Process() + { + auto opcode = ReadOpcode(); + lnt_.push_back({state_.GetAddress(), state_.GetLine()}); + while (opcode != Opcode::END_SEQUENCE) { + switch (opcode) { + case Opcode::ADVANCE_LINE: { + HandleAdvanceLine(); + break; + } + case Opcode::ADVANCE_PC: { + HandleAdvancePc(); + break; + } + case Opcode::SET_FILE: { + HandleSetFile(); + break; + } + case Opcode::SET_SOURCE_CODE: { + HandleSetSourceCode(); + break; + } + case Opcode::SET_PROLOGUE_END: + case Opcode::SET_EPILOGUE_BEGIN: + break; + case Opcode::START_LOCAL: { + HandleStartLocal(); + break; + } + case Opcode::START_LOCAL_EXTENDED: { + HandleStartLocalExtended(); + break; + } + case Opcode::RESTART_LOCAL: { + LOG(FATAL, ECMASCRIPT) << "Opcode RESTART_LOCAL is not supported"; + break; + } + case Opcode::END_LOCAL: { + HandleEndLocal(); + break; + } + case Opcode::SET_COLUMN: { + HandleSetColumn(); + break; + } + default: { + HandleSpecialOpcode(opcode); + break; + } + } + opcode = ReadOpcode(); + } + // process end offset + } + + LineNumberTable GetLineNumberTable() const + { + return lnt_; + } + + ColumnNumberTable GetColumnNumberTable() const + { + return cnt_; + } + + LocalVariableTable GetLocalVariableTable() const + { + return lvt_; + } + + const uint8_t *GetFile() const + { + return state_.GetFile(); + } + + const uint8_t *GetSourceCode() const + { + return state_.GetSourceCode(); + } + +private: + using Opcode = LineNumberProgramItem::Opcode; + + Opcode ReadOpcode() + { + auto opcode = static_cast(*program_); + ++program_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return opcode; + } + + int32_t ReadRegisterNumber() + { + auto [regiserNumber, n, isFull] = leb128::DecodeSigned(program_); + LOG_IF(!isFull, FATAL, ECMASCRIPT) << "Cannot read a register number"; + program_ += n; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return regiserNumber; + } + + void HandleAdvanceLine() + { + auto line_diff = state_.ReadSLeb128(); + state_.AdvanceLine(line_diff); + } + + void HandleAdvancePc() + { + auto pc_diff = state_.ReadULeb128(); + state_.AdvancePc(pc_diff); + } + + void HandleSetFile() + { + state_.SetFile(state_.ReadULeb128()); + } + + void HandleSetSourceCode() + { + state_.SetSourceCode(state_.ReadULeb128()); + } + + void HandleSetPrologueEnd() {} + + void HandleSetEpilogueBegin() {} + + void HandleStartLocal() + { + auto regNumber = ReadRegisterNumber(); + auto nameIndex = state_.ReadULeb128(); + [[maybe_unused]] auto typeIndex = state_.ReadULeb128(); + const char *name = GetStringFromConstantPool(state_.GetPandaFile(), nameIndex); + lvt_.insert(std::make_pair(name, regNumber)); + } + + void HandleStartLocalExtended() + { + auto regNumber = ReadRegisterNumber(); + auto nameIndex = state_.ReadULeb128(); + [[maybe_unused]] auto typeIndex = state_.ReadULeb128(); + [[maybe_unused]] auto typeSignatureIndex = state_.ReadULeb128(); + const char *name = GetStringFromConstantPool(state_.GetPandaFile(), nameIndex); + lvt_.insert(std::make_pair(name, regNumber)); + } + + void HandleEndLocal() + { + [[maybe_unused]] auto regNumber = ReadRegisterNumber(); + // process end offset + } + + void HandleSetColumn() + { + auto cn = state_.ReadULeb128(); + state_.SetColumn(cn); + cnt_.push_back({state_.GetAddress(), state_.GetColumn()}); + } + + void HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode) + { + ASSERT(static_cast(opcode) >= LineNumberProgramItem::OPCODE_BASE); + + auto adjustOpcode = static_cast(static_cast(opcode) - LineNumberProgramItem::OPCODE_BASE); + auto pcOffset = static_cast(adjustOpcode / LineNumberProgramItem::LINE_RANGE); + int32_t lineOffset = + static_cast(adjustOpcode) % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE; + state_.AdvancePc(pcOffset); + state_.AdvanceLine(lineOffset); + lnt_.push_back({state_.GetAddress(), state_.GetLine()}); + } + + LineProgramState state_; + const uint8_t *program_; + LineNumberTable lnt_; + LocalVariableTable lvt_; + ColumnNumberTable cnt_; +}; + +void DebugInfoExtractor::Extract(const panda_file::File *pf) +{ + ASSERT(pf != nullptr); + const auto &pandaFile = *pf; + auto classes = pf->GetClasses(); + for (size_t i = 0; i < classes.Size(); i++) { + panda_file::File::EntityId id(classes[i]); + if (pandaFile.IsExternal(id)) { + continue; + } + + ClassDataAccessor cda(pandaFile, id); + + auto sourceFileId = cda.GetSourceFileId(); + + cda.EnumerateMethods([&](MethodDataAccessor &mda) { + auto debugInfoId = mda.GetDebugInfoId(); + if (!debugInfoId) { + return; + } + + DebugInfoDataAccessor dda(pandaFile, debugInfoId.value()); + const uint8_t *program = dda.GetLineNumberProgram(); + LineProgramState state(pandaFile, sourceFileId.value_or(panda_file::File::EntityId(0)), dda.GetLineStart(), + dda.GetConstantPool()); + + LineNumberProgramProcessor programProcessor(state, program); + programProcessor.Process(); + + panda_file::File::EntityId methodId = mda.GetMethodId(); + const char *sourceFile = utf::Mutf8AsCString(programProcessor.GetFile()); + const char *sourceCode = utf::Mutf8AsCString(programProcessor.GetSourceCode()); + methods_.insert(std::make_pair(methodId.GetOffset(), MethodDebugInfo {sourceFile, sourceCode, + programProcessor.GetLineNumberTable(), + programProcessor.GetColumnNumberTable(), + programProcessor.GetLocalVariableTable()})); + }); + } +} + +const LineNumberTable &DebugInfoExtractor::GetLineNumberTable(panda_file::File::EntityId methodId) const +{ + static const LineNumberTable EMPTY_LINE_TABLE {}; + + auto iter = methods_.find(methodId.GetOffset()); + if (iter == methods_.end()) { + return EMPTY_LINE_TABLE; + } + return iter->second.lineNumberTable; +} + +const ColumnNumberTable &DebugInfoExtractor::GetColumnNumberTable(panda_file::File::EntityId methodId) const +{ + static const ColumnNumberTable EMPTY_COLUMN_TABLE {}; + + auto iter = methods_.find(methodId.GetOffset()); + if (iter == methods_.end()) { + return EMPTY_COLUMN_TABLE; + } + return iter->second.columnNumberTable; +} + +const LocalVariableTable &DebugInfoExtractor::GetLocalVariableTable(panda_file::File::EntityId methodId) const +{ + static const LocalVariableTable EMPTY_VARIABLE_TABLE {}; + + auto iter = methods_.find(methodId.GetOffset()); + if (iter == methods_.end()) { + return EMPTY_VARIABLE_TABLE; + } + return iter->second.localVariableTable; +} + +const char *DebugInfoExtractor::GetSourceFile(panda_file::File::EntityId methodId) const +{ + auto iter = methods_.find(methodId.GetOffset()); + if (iter == methods_.end()) { + return ""; + } + return iter->second.sourceFile.c_str(); +} + +const char *DebugInfoExtractor::GetSourceCode(panda_file::File::EntityId methodId) const +{ + auto iter = methods_.find(methodId.GetOffset()); + if (iter == methods_.end()) { + return ""; + } + return iter->second.sourceCode.c_str(); +} + +std::vector DebugInfoExtractor::GetMethodIdList() const +{ + std::vector list; + + for (const auto &method : methods_) { + list.push_back(panda_file::File::EntityId(method.first)); + } + return list; +} +} // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/debug_info_extractor.h b/ecmascript/jspandafile/debug_info_extractor.h new file mode 100644 index 000000000..759095b0d --- /dev/null +++ b/ecmascript/jspandafile/debug_info_extractor.h @@ -0,0 +1,87 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H +#define ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H + +#include +#include + +#include "ecmascript/common.h" +#include "libpandafile/file.h" + +namespace panda::ecmascript { +struct LineTableEntry { + uint32_t offset; + size_t line; +}; + +struct ColumnTableEntry { + uint32_t offset; + size_t column; +}; + +using LineNumberTable = std::vector; +using ColumnNumberTable = std::vector; + +/* + * LocalVariableInfo define in frontend, now only use name and regNumber: + * std::string name + * std::string type + * std::string typeSignature + * int32_t regNumber + * uint32_t startOffset + * uint32_t endOffset + */ +using LocalVariableTable = std::unordered_map; + +// public for debugger +class PUBLIC_API DebugInfoExtractor { +public: + explicit DebugInfoExtractor(const panda_file::File *pf); + + ~DebugInfoExtractor() = default; + + DEFAULT_COPY_SEMANTIC(DebugInfoExtractor); + DEFAULT_MOVE_SEMANTIC(DebugInfoExtractor); + + const LineNumberTable &GetLineNumberTable(panda_file::File::EntityId methodId) const; + + const ColumnNumberTable &GetColumnNumberTable(panda_file::File::EntityId methodId) const; + + const LocalVariableTable &GetLocalVariableTable(panda_file::File::EntityId methodId) const; + + const char *GetSourceFile(panda_file::File::EntityId methodId) const; + + const char *GetSourceCode(panda_file::File::EntityId methodId) const; + + std::vector GetMethodIdList() const; + +private: + void Extract(const panda_file::File *pf); + + struct MethodDebugInfo { + std::string sourceFile; + std::string sourceCode; + LineNumberTable lineNumberTable; + ColumnNumberTable columnNumberTable; + LocalVariableTable localVariableTable; + }; + + std::unordered_map methods_; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H diff --git a/ecmascript/jspandafile/js_pandafile.cpp b/ecmascript/jspandafile/js_pandafile.cpp index aa265ce1f..c3258db47 100644 --- a/ecmascript/jspandafile/js_pandafile.cpp +++ b/ecmascript/jspandafile/js_pandafile.cpp @@ -37,15 +37,6 @@ JSPandaFile::~JSPandaFile() } } -tooling::ecmascript::PtJSExtractor *JSPandaFile::GetOrCreatePtJSExtractor() -{ - if (ptJSExtractor_) { - return ptJSExtractor_.get(); - } - ptJSExtractor_ = std::make_unique(pf_); - return ptJSExtractor_.get(); -} - uint32_t JSPandaFile::GetOrInsertConstantPool(ConstPoolType type, uint32_t offset) { auto it = constpoolMap_.find(offset); diff --git a/ecmascript/jspandafile/js_pandafile.h b/ecmascript/jspandafile/js_pandafile.h index f94b8fd5a..e6b4f6fb3 100644 --- a/ecmascript/jspandafile/js_pandafile.h +++ b/ecmascript/jspandafile/js_pandafile.h @@ -16,10 +16,10 @@ #ifndef ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_H #define ECMASCRIPT_JSPANDAFILE_JS_PANDAFILE_H +#include "ecmascript/js_method.h" #include "ecmascript/jspandafile/constpool_value.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/mem/c_containers.h" -#include "ecmascript/tooling/pt_js_extractor.h" #include "libpandafile/file.h" #include "libpandabase/utils/logger.h" @@ -38,8 +38,6 @@ public: JSPandaFile(const panda_file::File *pf, const std::string &descriptor); ~JSPandaFile(); - tooling::ecmascript::PtJSExtractor *GetOrCreatePtJSExtractor(); - const std::string &GetJSPandaFileDesc() const { return desc_; @@ -108,7 +106,6 @@ private: JSMethod *methods_ {nullptr}; std::unordered_map methodMap_; const panda_file::File *pf_ {nullptr}; - std::unique_ptr ptJSExtractor_; std::string desc_; bool isModule_ {false}; }; diff --git a/ecmascript/jspandafile/js_pandafile_manager.cpp b/ecmascript/jspandafile/js_pandafile_manager.cpp index 3426ddf5c..19a8018e7 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.cpp +++ b/ecmascript/jspandafile/js_pandafile_manager.cpp @@ -182,15 +182,22 @@ void JSPandaFileManager::ReleaseJSPandaFile(const JSPandaFile *jsPandaFile) delete jsPandaFile; } -tooling::ecmascript::PtJSExtractor *JSPandaFileManager::GetPtJSExtractor(const JSPandaFile *jsPandaFile) +tooling::ecmascript::JSPtExtractor *JSPandaFileManager::GetJSPtExtractor(const JSPandaFile *jsPandaFile) { + LOG_IF(jsPandaFile == nullptr, FATAL, ECMASCRIPT) << "GetJSPtExtractor error, js pandafile is nullptr"; + os::memory::LockHolder lock(jsPandaFileLock_); - auto iter = loadedJSPandaFiles_.find(jsPandaFile); - if (iter == loadedJSPandaFiles_.end()) { - LOG_ECMA(FATAL) << "can not get PtJSExtrjsPandaFile from unknown jsPandaFile"; - return nullptr; + ASSERT(loadedJSPandaFiles_.find(jsPandaFile) != loadedJSPandaFiles_.end()); + + auto iter = extractors_.find(jsPandaFile); + if (iter == extractors_.end()) { + auto extractorPtr = std::make_unique(jsPandaFile->GetPandaFile()); + tooling::ecmascript::JSPtExtractor *extractor = extractorPtr.get(); + extractors_[jsPandaFile] = std::move(extractorPtr); + return extractor; } - return const_cast(jsPandaFile)->GetOrCreatePtJSExtractor(); + + return iter->second.get(); } const JSPandaFile *JSPandaFileManager::GenerateJSPandaFile(const panda_file::File *pf, const std::string &desc) diff --git a/ecmascript/jspandafile/js_pandafile_manager.h b/ecmascript/jspandafile/js_pandafile_manager.h index 7bdc2f086..d8241450a 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.h +++ b/ecmascript/jspandafile/js_pandafile_manager.h @@ -19,7 +19,7 @@ #include "ecmascript/mem/c_containers.h" #include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/panda_file_translator.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/js_pt_extractor.h" #include "libpandafile/file.h" #include "libpandabase/utils/logger.h" @@ -55,7 +55,7 @@ public: JSPandaFile *NewJSPandaFile(const panda_file::File *pf, const std::string &desc); - tooling::ecmascript::PtJSExtractor *GetPtJSExtractor(const JSPandaFile *jsPandaFile); + tooling::ecmascript::JSPtExtractor *GetJSPtExtractor(const JSPandaFile *jsPandaFile); static void RemoveJSPandaFile(void *pointer, void *data); @@ -94,6 +94,7 @@ private: os::memory::RecursiveMutex jsPandaFileLock_; std::unordered_map loadedJSPandaFiles_; + std::unordered_map> extractors_; friend class JSPandaFile; }; diff --git a/ecmascript/jspandafile/panda_file_translator.cpp b/ecmascript/jspandafile/panda_file_translator.cpp index f318c702b..7d5e83aaf 100644 --- a/ecmascript/jspandafile/panda_file_translator.cpp +++ b/ecmascript/jspandafile/panda_file_translator.cpp @@ -72,8 +72,8 @@ void PandaFileTranslator::TranslateClasses(JSPandaFile *jsPandaFile, const CStri jsPandaFile->UpdateMainMethodIndex(mda.GetMethodId().GetOffset()); } - InitializeMemory(method, nullptr, jsPandaFile, mda.GetMethodId(), codeDataAccessor.GetCodeId(), - mda.GetAccessFlags(), codeDataAccessor.GetNumArgs(), nullptr); + InitializeMemory(method, jsPandaFile, mda.GetMethodId(), codeDataAccessor.GetCodeId(), + mda.GetAccessFlags(), codeDataAccessor.GetNumArgs()); method->SetHotnessCounter(EcmaInterpreter::METHOD_HOTNESS_THRESHOLD); method->InitializeCallField(); const uint8_t *insns = codeDataAccessor.GetInstructions(); @@ -88,29 +88,32 @@ void PandaFileTranslator::TranslateClasses(JSPandaFile *jsPandaFile, const CStri JSHandle PandaFileTranslator::GenerateProgram(EcmaVM *vm, const JSPandaFile *jsPandaFile) { - JSThread *thread = vm->GetJSThread(); - EcmaHandleScope handleScope(thread); - - JSHandle env = vm->GetGlobalEnv(); ObjectFactory *factory = vm->GetFactory(); JSHandle program = factory->NewProgram(); - uint32_t mainMethodIndex = jsPandaFile->GetMainMethodIndex(); - auto method = jsPandaFile->FindMethods(mainMethodIndex); - ASSERT(method != nullptr); - JSHandle dynclass = JSHandle::Cast(env->GetFunctionClassWithProto()); - JSHandle mainFunc = - factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::BASE_CONSTRUCTOR); + { + JSThread *thread = vm->GetJSThread(); + EcmaHandleScope handleScope(thread); - program->SetMainFunction(thread, mainFunc.GetTaggedValue()); + JSHandle env = vm->GetGlobalEnv(); - JSTaggedValue constpool = vm->FindConstpool(jsPandaFile); - if (constpool.IsHole()) { - constpool = ParseConstPool(vm, jsPandaFile); - vm->SetConstpool(jsPandaFile, constpool); - } + uint32_t mainMethodIndex = jsPandaFile->GetMainMethodIndex(); + auto method = jsPandaFile->FindMethods(mainMethodIndex); + ASSERT(method != nullptr); + JSHandle dynclass = JSHandle::Cast(env->GetFunctionClassWithProto()); + JSHandle mainFunc = + factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::BASE_CONSTRUCTOR); - mainFunc->SetConstantPool(thread, constpool); + program->SetMainFunction(thread, mainFunc.GetTaggedValue()); + + JSTaggedValue constpool = vm->FindConstpool(jsPandaFile); + if (constpool.IsHole()) { + constpool = ParseConstPool(vm, jsPandaFile); + vm->SetConstpool(jsPandaFile, constpool); + } + + mainFunc->SetConstantPool(thread, constpool); + } return program; } diff --git a/ecmascript/jspandafile/scope_info_extractor.cpp b/ecmascript/jspandafile/scope_info_extractor.cpp index da084104f..a7992692d 100644 --- a/ecmascript/jspandafile/scope_info_extractor.cpp +++ b/ecmascript/jspandafile/scope_info_extractor.cpp @@ -31,12 +31,13 @@ JSTaggedValue ScopeInfoExtractor::GenerateScopeInfo(JSThread *thread, uint16_t s auto buffer = ecmaVm->GetNativeAreaAllocator()->New(); auto scopeDebugInfo = static_cast(buffer); - scopeDebugInfo->scopeInfo.reserve(length); for (size_t i = 1; i < length; i += 2) { // 2: Each literal buffer contains a pair of key-value. - CString name = ConvertToString(elementsLiteral->Get(i)); + JSTaggedValue val = elementsLiteral->Get(i); + ASSERT(val.IsString()); + std::string name = base::StringHelper::ToStdString(EcmaString::Cast(val.GetTaggedObject())); uint32_t slot = elementsLiteral->Get(i + 1).GetInt(); - scopeDebugInfo->scopeInfo.push_back({slot, name}); + scopeDebugInfo->scopeInfo.insert(std::make_pair(name, slot)); } JSHandle pointer = factory->NewJSNativePointer( diff --git a/ecmascript/jspandafile/scope_info_extractor.h b/ecmascript/jspandafile/scope_info_extractor.h index ed7daa120..53c2b76f6 100644 --- a/ecmascript/jspandafile/scope_info_extractor.h +++ b/ecmascript/jspandafile/scope_info_extractor.h @@ -19,6 +19,10 @@ #include "ecmascript/js_tagged_value-inl.h" namespace panda::ecmascript { +struct ScopeDebugInfo { + std::unordered_map scopeInfo; +}; + class ScopeInfoExtractor { public: explicit ScopeInfoExtractor() = default; diff --git a/ecmascript/lexical_env.h b/ecmascript/lexical_env.h index d52ee099c..4aa0ff4b7 100644 --- a/ecmascript/lexical_env.h +++ b/ecmascript/lexical_env.h @@ -19,15 +19,6 @@ #include "ecmascript/js_object.h" namespace panda::ecmascript { -struct ScopeInfo { - uint32_t slot; - CString name; -}; - -struct ScopeDebugInfo { - std::vector scopeInfo; -}; - class LexicalEnv : public TaggedArray { public: static constexpr uint32_t PARENT_ENV_INDEX = 0; diff --git a/ecmascript/tooling/BUILD.gn b/ecmascript/tooling/BUILD.gn index 12822eebf..6921fadce 100644 --- a/ecmascript/tooling/BUILD.gn +++ b/ecmascript/tooling/BUILD.gn @@ -36,8 +36,8 @@ debugger_sources = [ "base/pt_types.cpp", "debugger_service.cpp", "dispatcher.cpp", + "js_pt_extractor.cpp", "protocol_handler.cpp", - "pt_js_extractor.cpp", ] source_set("libark_ecma_debugger_static") { diff --git a/ecmascript/tooling/agent/js_backend.cpp b/ecmascript/tooling/agent/js_backend.cpp index f4b708ee4..5f36d59dd 100644 --- a/ecmascript/tooling/agent/js_backend.cpp +++ b/ecmascript/tooling/agent/js_backend.cpp @@ -60,7 +60,7 @@ void JSBackend::NotifyPaused(std::optional location, PauseReason rea CVector hitBreakpoints; if (location.has_value()) { BreakpointDetails detail; - PtJSExtractor *extractor = nullptr; + JSPtExtractor *extractor = nullptr; auto scriptFunc = [this, &extractor, &detail](PtScript *script) -> bool { detail.url_ = script->GetUrl(); extractor = GetExtractor(detail.url_); @@ -124,24 +124,9 @@ bool JSBackend::NotifyScriptParsed(int32_t scriptId, const CString &fileName) return false; } - auto classes = pfs->GetClasses(); - ASSERT(classes.Size() > 0); - size_t index = 0; - for (; index < classes.Size(); index++) { - if (!(*pfs).IsExternal(panda_file::File::EntityId(classes[index]))) { - break; - } - } - panda_file::ClassDataAccessor cda(*pfs, panda_file::File::EntityId(classes[index])); - auto lang = cda.GetSourceLang(); - if (lang.value_or(panda_file::SourceLang::PANDA_ASSEMBLY) != panda_file::SourceLang::ECMASCRIPT) { - LOG(ERROR, DEBUGGER) << "NotifyScriptParsed: Unsupported file: " << fileName; - return false; - } - CString url; CString source; - PtJSExtractor *extractor = GenerateExtractor(pfs); + JSPtExtractor *extractor = GenerateExtractor(pfs); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "NotifyScriptParsed: Unsupported file: " << fileName; return false; @@ -174,7 +159,7 @@ bool JSBackend::NotifyScriptParsed(int32_t scriptId, const CString &fileName) bool JSBackend::StepComplete(const PtLocation &location) { - PtJSExtractor *extractor = nullptr; + JSPtExtractor *extractor = nullptr; auto scriptFunc = [this, &extractor](PtScript *script) -> bool { extractor = GetExtractor(script->GetUrl()); return true; @@ -201,7 +186,7 @@ bool JSBackend::StepComplete(const PtLocation &location) std::optional JSBackend::GetPossibleBreakpoints(Location *start, [[maybe_unused]] Location *end, CVector> *locations) { - PtJSExtractor *extractor = nullptr; + JSPtExtractor *extractor = nullptr; auto scriptFunc = [this, &extractor](PtScript *script) -> bool { extractor = GetExtractor(script->GetUrl()); return true; @@ -227,7 +212,7 @@ std::optional JSBackend::GetPossibleBreakpoints(Location *start, [[maybe_ std::optional JSBackend::SetBreakpointByUrl(const CString &url, size_t lineNumber, size_t columnNumber, CString *out_id, CVector> *outLocations) { - PtJSExtractor *extractor = GetExtractor(url); + JSPtExtractor *extractor = GetExtractor(url); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: extractor is null"; return Error(Error::Type::METHOD_NOT_FOUND, "Extractor not found"); @@ -270,7 +255,7 @@ std::optional JSBackend::SetBreakpointByUrl(const CString &url, size_t li std::optional JSBackend::RemoveBreakpoint(const BreakpointDetails &metaData) { - PtJSExtractor *extractor = GetExtractor(metaData.url_); + JSPtExtractor *extractor = GetExtractor(metaData.url_); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "RemoveBreakpoint: extractor is null"; return Error(Error::Type::METHOD_NOT_FOUND, "Extractor not found"); @@ -319,7 +304,7 @@ std::optional JSBackend::Resume() std::optional JSBackend::StepInto() { JSMethod *method = DebuggerApi::GetMethod(ecmaVm_); - PtJSExtractor *extractor = GetExtractor(method->GetPandaFile()); + JSPtExtractor *extractor = GetExtractor(method->GetPandaFile()); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "StepInto: extractor is null"; return Error(Error::Type::METHOD_NOT_FOUND, "Extractor not found"); @@ -334,7 +319,7 @@ std::optional JSBackend::StepInto() std::optional JSBackend::StepOver() { JSMethod *method = DebuggerApi::GetMethod(ecmaVm_); - PtJSExtractor *extractor = GetExtractor(method->GetPandaFile()); + JSPtExtractor *extractor = GetExtractor(method->GetPandaFile()); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "StepOver: extractor is null"; return Error(Error::Type::METHOD_NOT_FOUND, "Extractor not found"); @@ -349,7 +334,7 @@ std::optional JSBackend::StepOver() std::optional JSBackend::StepOut() { JSMethod *method = DebuggerApi::GetMethod(ecmaVm_); - PtJSExtractor *extractor = GetExtractor(method->GetPandaFile()); + JSPtExtractor *extractor = GetExtractor(method->GetPandaFile()); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "StepOut: extractor is null"; return Error(Error::Type::METHOD_NOT_FOUND, "Extractor not found"); @@ -371,7 +356,7 @@ std::optional JSBackend::EvaluateValue(const CString &callFrameId, const Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, "Runtime internal error"))); return Error(Error::Type::METHOD_NOT_FOUND, "Native Frame not support"); } - DebugInfoExtractor *extractor = GetExtractor(method->GetPandaFile()); + JSPtExtractor *extractor = GetExtractor(method->GetPandaFile()); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "EvaluateValue: extractor is null"; *result = RemoteObject::FromTagged(ecmaVm_, @@ -394,10 +379,9 @@ std::optional JSBackend::EvaluateValue(const CString &callFrameId, const int32_t regIndex = -1; auto varInfos = extractor->GetLocalVariableTable(method->GetFileId()); - for (const auto &varInfo : varInfos) { - if (varInfo.name == std::string(varName)) { - regIndex = varInfo.reg_number; - } + auto iter = varInfos.find(varName.c_str()); + if (iter != varInfos.end()) { + regIndex = iter->second; } if (regIndex != -1) { if (varValue.empty()) { @@ -407,7 +391,7 @@ std::optional JSBackend::EvaluateValue(const CString &callFrameId, const } int32_t level = 0; uint32_t slot = 0; - if (!DebuggerApi::EvaluateLexicalValue(ecmaVm_, varName, level, slot)) { + if (!DebuggerApi::EvaluateLexicalValue(ecmaVm_, varName.c_str(), level, slot)) { *result = RemoteObject::FromTagged(ecmaVm_, Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, "Unknown input params"))); return Error(Error::Type::METHOD_NOT_FOUND, "Unsupported expression"); @@ -428,18 +412,18 @@ CString JSBackend::Trim(const CString &str) return ret; } -PtJSExtractor *JSBackend::GenerateExtractor(const panda_file::File *file) +JSPtExtractor *JSBackend::GenerateExtractor(const panda_file::File *file) { if (file->GetFilename().substr(0, DATA_APP_PATH.length()) != DATA_APP_PATH) { return nullptr; } - auto extractor = std::make_unique(file); - PtJSExtractor *res = extractor.get(); + auto extractor = std::make_unique(file); + JSPtExtractor *res = extractor.get(); extractors_[file->GetFilename()] = std::move(extractor); return res; } -PtJSExtractor *JSBackend::GetExtractor(const panda_file::File *file) +JSPtExtractor *JSBackend::GetExtractor(const panda_file::File *file) { const std::string fileName = file->GetFilename(); if (extractors_.find(fileName) == extractors_.end()) { @@ -449,7 +433,7 @@ PtJSExtractor *JSBackend::GetExtractor(const panda_file::File *file) return extractors_[fileName].get(); } -PtJSExtractor *JSBackend::GetExtractor(const CString &url) +JSPtExtractor *JSBackend::GetExtractor(const CString &url) { for (const auto &iter : extractors_) { auto methods = iter.second->GetMethodIdList(); @@ -491,7 +475,7 @@ bool JSBackend::GenerateCallFrame(CallFrame *callFrame, { JSMethod *method = DebuggerApi::GetMethod(frameHandler); auto *pf = method->GetPandaFile(); - PtJSExtractor *extractor = GetExtractor(pf); + JSPtExtractor *extractor = GetExtractor(pf); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "GenerateCallFrame: extractor is null"; return false; @@ -551,7 +535,7 @@ std::unique_ptr JSBackend::GetLocalScopeChain(const InterpretedFrameHandl .SetDescription(RemoteObject::ObjectDescription); propertiesPair_[curObjectId_++] = Global(ecmaVm_, localObject); - PtJSExtractor *extractor = GetExtractor(DebuggerApi::GetMethod(frameHandler)->GetPandaFile()); + JSPtExtractor *extractor = GetExtractor(DebuggerApi::GetMethod(frameHandler)->GetPandaFile()); if (extractor == nullptr) { LOG(ERROR, DEBUGGER) << "GetScopeChain: extractor is null"; return localScope; @@ -560,23 +544,22 @@ std::unique_ptr JSBackend::GetLocalScopeChain(const InterpretedFrameHandl Local name = JSValueRef::Undefined(ecmaVm_); Local value = JSValueRef::Undefined(ecmaVm_); for (const auto &var : extractor->GetLocalVariableTable(methodId)) { - value = DebuggerApi::GetVRegValue(ecmaVm_, frameHandler, var.reg_number); - if (var.name == "this") { + value = DebuggerApi::GetVRegValue(ecmaVm_, frameHandler, var.second); + if (var.first == "this") { *thisObj = RemoteObject::FromTagged(ecmaVm_, value); if (value->IsObject() && !value->IsProxy()) { (*thisObj)->SetObjectId(curObjectId_); propertiesPair_[curObjectId_++] = Global(ecmaVm_, value); } } else { - name = StringRef::NewFromUtf8(ecmaVm_, var.name.c_str()); + name = StringRef::NewFromUtf8(ecmaVm_, var.first.c_str()); PropertyAttribute descriptor(value, true, true, true); localObject->DefineProperty(ecmaVm_, name, descriptor); } } if ((*thisObj)->GetType() == ObjectType::Undefined) { - const CString targetName = "this"; - value = DebuggerApi::GetLexicalValueInfo(ecmaVm_, targetName); + value = DebuggerApi::GetLexicalValueInfo(ecmaVm_, "this"); *thisObj = RemoteObject::FromTagged(ecmaVm_, value); if (value->IsObject() && !value->IsProxy()) { (*thisObj)->SetObjectId(curObjectId_); @@ -584,7 +567,7 @@ std::unique_ptr JSBackend::GetLocalScopeChain(const InterpretedFrameHandl } } - const panda_file::LineNumberTable &lines = extractor->GetLineNumberTable(methodId); + auto lines = extractor->GetLineNumberTable(methodId); std::unique_ptr startLoc = std::make_unique(); std::unique_ptr endLoc = std::make_unique(); auto scriptFunc = [&startLoc, &endLoc, lines](PtScript *script) -> bool { diff --git a/ecmascript/tooling/agent/js_backend.h b/ecmascript/tooling/agent/js_backend.h index 32886ecb5..8dc5e6c8f 100644 --- a/ecmascript/tooling/agent/js_backend.h +++ b/ecmascript/tooling/agent/js_backend.h @@ -19,7 +19,7 @@ #include "ecmascript/tooling/agent/js_pt_hooks.h" #include "ecmascript/tooling/base/pt_types.h" #include "ecmascript/tooling/dispatcher.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/js_pt_extractor.h" #include "libpandabase/macros.h" namespace panda::tooling::ecmascript { @@ -115,9 +115,9 @@ private: NO_MOVE_SEMANTIC(JSBackend); NO_COPY_SEMANTIC(JSBackend); CString Trim(const CString &str); - PtJSExtractor *GenerateExtractor(const panda_file::File *file); - PtJSExtractor *GetExtractor(const panda_file::File *file); - PtJSExtractor *GetExtractor(const CString &url); + JSPtExtractor *GenerateExtractor(const panda_file::File *file); + JSPtExtractor *GetExtractor(const panda_file::File *file); + JSPtExtractor *GetExtractor(const CString &url); bool GenerateCallFrame(CallFrame *callFrame, const InterpretedFrameHandler *frameHandler, int32_t frameId); std::unique_ptr GetLocalScopeChain(const InterpretedFrameHandler *frameHandler, std::unique_ptr *thisObj); @@ -137,13 +137,13 @@ private: const EcmaVM *ecmaVm_ {nullptr}; std::unique_ptr hooks_ {nullptr}; JSDebugger *debugger_ {nullptr}; - CMap> extractors_ {}; + CMap> extractors_ {}; CMap> scripts_ {}; CMap> propertiesPair_ {}; uint32_t curObjectId_ {0}; bool pauseOnException_ {false}; bool pauseOnNextByteCode_ {false}; - std::unique_ptr singleStepper_ {nullptr}; + std::unique_ptr singleStepper_ {nullptr}; friend class JSPtHooks; }; diff --git a/ecmascript/tooling/agent/js_pt_hooks.h b/ecmascript/tooling/agent/js_pt_hooks.h index 5b3ecc983..5de576cf5 100644 --- a/ecmascript/tooling/agent/js_pt_hooks.h +++ b/ecmascript/tooling/agent/js_pt_hooks.h @@ -17,7 +17,7 @@ #define ECMASCRIPT_TOOLING_AGENT_JS_PT_HOOKS_H #include "libpandabase/macros.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/js_pt_extractor.h" #include "ecmascript/tooling/base/pt_events.h" #include "ecmascript/tooling/base/pt_script.h" #include "include/tooling/debug_interface.h" diff --git a/ecmascript/tooling/interface/debugger_api.cpp b/ecmascript/tooling/interface/debugger_api.cpp index 3f22e2624..0d567e360 100644 --- a/ecmascript/tooling/interface/debugger_api.cpp +++ b/ecmascript/tooling/interface/debugger_api.cpp @@ -224,7 +224,7 @@ void DebuggerApi::SetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t sl LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(ecmaVm->GetJSThread(), slot, target); } -bool DebuggerApi::EvaluateLexicalValue(const EcmaVM *ecmaVm, const CString &name, int32_t &level, uint32_t &slot) +bool DebuggerApi::EvaluateLexicalValue(const EcmaVM *ecmaVm, const std::string &name, int32_t &level, uint32_t &slot) { JSTaggedValue curEnv = ecmaVm->GetJSThread()->GetCurrentLexenv(); for (; curEnv.IsTaggedArray(); curEnv = LexicalEnv::Cast(curEnv.GetTaggedObject())->GetParentEnv()) { @@ -235,17 +235,17 @@ bool DebuggerApi::EvaluateLexicalValue(const EcmaVM *ecmaVm, const CString &name } auto result = JSNativePointer::Cast(lexicalEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer(); ScopeDebugInfo *scopeDebugInfo = reinterpret_cast(result); - for (const auto &info : scopeDebugInfo->scopeInfo) { - if (info.name == name) { - slot = info.slot; - return true; - } + auto iter = scopeDebugInfo->scopeInfo.find(name); + if (iter == scopeDebugInfo->scopeInfo.end()) { + continue; } + slot = iter->second; + return true; } return false; } -Local DebuggerApi::GetLexicalValueInfo(const EcmaVM *ecmaVm, const CString &name) +Local DebuggerApi::GetLexicalValueInfo(const EcmaVM *ecmaVm, const std::string &name) { JSThread *thread = ecmaVm->GetJSThread(); JSTaggedValue curEnv = thread->GetCurrentLexenv(); @@ -256,14 +256,14 @@ Local DebuggerApi::GetLexicalValueInfo(const EcmaVM *ecmaVm, const C } void *pointer = JSNativePointer::Cast(lexicalEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer(); ScopeDebugInfo *scopeDebugInfo = static_cast(pointer); - for (const auto &info : scopeDebugInfo->scopeInfo) { - if (info.name == name) { - uint16_t slot = info.slot; - JSTaggedValue value = lexicalEnv->GetProperties(slot); - JSHandle handledValue(thread, value); - return JSNApiHelper::ToLocal(handledValue); - } + auto iter = scopeDebugInfo->scopeInfo.find(name); + if (iter == scopeDebugInfo->scopeInfo.end()) { + continue; } + uint32_t slot = iter->second; + JSTaggedValue value = lexicalEnv->GetProperties(slot); + JSHandle handledValue(thread, value); + return JSNApiHelper::ToLocal(handledValue); } JSHandle handledValue(thread, JSTaggedValue::Hole()); return JSNApiHelper::ToLocal(handledValue); diff --git a/ecmascript/tooling/interface/debugger_api.h b/ecmascript/tooling/interface/debugger_api.h index 5b20a1b14..737e080fb 100644 --- a/ecmascript/tooling/interface/debugger_api.h +++ b/ecmascript/tooling/interface/debugger_api.h @@ -97,8 +97,8 @@ public: // ScopeInfo static Local GetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t slot); static void SetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t slot, Local value); - static bool EvaluateLexicalValue(const EcmaVM *ecmaVm, const CString &name, int32_t &level, uint32_t &slot); - static Local GetLexicalValueInfo(const EcmaVM *ecmaVm, const CString &name); + static bool EvaluateLexicalValue(const EcmaVM *ecmaVm, const std::string &name, int32_t &level, uint32_t &slot); + static Local GetLexicalValueInfo(const EcmaVM *ecmaVm, const std::string &name); }; } // namespace panda::tooling::ecmascript diff --git a/ecmascript/tooling/pt_js_extractor.cpp b/ecmascript/tooling/js_pt_extractor.cpp similarity index 84% rename from ecmascript/tooling/pt_js_extractor.cpp rename to ecmascript/tooling/js_pt_extractor.cpp index 98b6f863b..44c6d8098 100644 --- a/ecmascript/tooling/pt_js_extractor.cpp +++ b/ecmascript/tooling/js_pt_extractor.cpp @@ -14,17 +14,17 @@ */ #include "ecmascript/tooling/interface/debugger_api.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/js_pt_extractor.h" namespace panda::tooling::ecmascript { using panda::ecmascript::InterpretedFrameHandler; using panda::ecmascript::JSTaggedType; -uint32_t PtJSExtractor::SingleStepper::GetStackDepth() const +uint32_t JSPtExtractor::SingleStepper::GetStackDepth() const { return DebuggerApi::GetStackDepth(ecmaVm_); } -bool PtJSExtractor::SingleStepper::InStepRange(uint32_t pc) const +bool JSPtExtractor::SingleStepper::InStepRange(uint32_t pc) const { for (const auto &range : stepRanges_) { if (pc >= range.start_bc_offset && pc < range.end_bc_offset) { @@ -34,7 +34,7 @@ bool PtJSExtractor::SingleStepper::InStepRange(uint32_t pc) const return false; } -bool PtJSExtractor::SingleStepper::StepComplete(uint32_t bcOffset) const +bool JSPtExtractor::SingleStepper::StepComplete(uint32_t bcOffset) const { JSMethod *method = DebuggerApi::GetMethod(ecmaVm_); uint32_t stackDepth = GetStackDepth(); @@ -55,7 +55,7 @@ bool PtJSExtractor::SingleStepper::StepComplete(uint32_t bcOffset) const } break; } - case SingleStepper::Type::OUT: { + case Type::OUT: { if (stackDepth_ <= stackDepth) { return false; } @@ -69,22 +69,22 @@ bool PtJSExtractor::SingleStepper::StepComplete(uint32_t bcOffset) const return true; } -std::unique_ptr PtJSExtractor::GetStepIntoStepper(const EcmaVM *ecmaVm) +std::unique_ptr JSPtExtractor::GetStepIntoStepper(const EcmaVM *ecmaVm) { return GetStepper(ecmaVm, SingleStepper::Type::INTO); } -std::unique_ptr PtJSExtractor::GetStepOverStepper(const EcmaVM *ecmaVm) +std::unique_ptr JSPtExtractor::GetStepOverStepper(const EcmaVM *ecmaVm) { return GetStepper(ecmaVm, SingleStepper::Type::OVER); } -std::unique_ptr PtJSExtractor::GetStepOutStepper(const EcmaVM *ecmaVm) +std::unique_ptr JSPtExtractor::GetStepOutStepper(const EcmaVM *ecmaVm) { return GetStepper(ecmaVm, SingleStepper::Type::OUT); } -CList PtJSExtractor::GetStepRanges(File::EntityId methodId, uint32_t offset) +CList JSPtExtractor::GetStepRanges(File::EntityId methodId, uint32_t offset) { CList ranges {}; auto table = GetLineNumberTable(methodId); @@ -103,7 +103,7 @@ CList PtJSExtractor::GetStepRanges(File::EntityId methodId, uint32_ return ranges; } -std::unique_ptr PtJSExtractor::GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type) +std::unique_ptr JSPtExtractor::GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type) { JSMethod *method = DebuggerApi::GetMethod(ecmaVm); ASSERT(method != nullptr); diff --git a/ecmascript/tooling/pt_js_extractor.h b/ecmascript/tooling/js_pt_extractor.h similarity index 89% rename from ecmascript/tooling/pt_js_extractor.h rename to ecmascript/tooling/js_pt_extractor.h index 0c6f4d97a..3909dabc8 100644 --- a/ecmascript/tooling/pt_js_extractor.h +++ b/ecmascript/tooling/js_pt_extractor.h @@ -13,24 +13,24 @@ * limitations under the License. */ -#ifndef PANDA_TOOLING_JS_EXTRACTOR_H -#define PANDA_TOOLING_JS_EXTRACTOR_H +#ifndef ECMASCRIPT_TOOLING_JS_PT_EXTRACTOR_H +#define ECMASCRIPT_TOOLING_JS_PT_EXTRACTOR_H #include "ecmascript/js_method.h" #include "ecmascript/js_thread.h" +#include "ecmascript/jspandafile/debug_info_extractor.h" #include "ecmascript/mem/c_containers.h" -#include "libpandafile/debug_info_extractor.h" #include "libpandabase/macros.h" #include "include/tooling/debug_interface.h" namespace panda::tooling::ecmascript { using panda::ecmascript::CList; +using panda::ecmascript::DebugInfoExtractor; using panda::ecmascript::EcmaVM; using panda::ecmascript::JSMethod; -using panda::panda_file::DebugInfoExtractor; using panda::panda_file::File; -class PtJSExtractor : public DebugInfoExtractor { +class JSPtExtractor : public DebugInfoExtractor { public: class SingleStepper { public: @@ -60,8 +60,8 @@ public: Type type_; }; - explicit PtJSExtractor(const File *pf) : DebugInfoExtractor(pf) {} - virtual ~PtJSExtractor() = default; + explicit JSPtExtractor(const File *pf) : DebugInfoExtractor(pf) {} + virtual ~JSPtExtractor() = default; template bool MatchWithLocation(const Callback &cb, size_t line, size_t column) @@ -122,10 +122,10 @@ public: std::unique_ptr GetStepOutStepper(const EcmaVM *ecmaVm); private: - NO_COPY_SEMANTIC(PtJSExtractor); - NO_MOVE_SEMANTIC(PtJSExtractor); + NO_COPY_SEMANTIC(JSPtExtractor); + NO_MOVE_SEMANTIC(JSPtExtractor); CList GetStepRanges(File::EntityId methodId, uint32_t offset); std::unique_ptr GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type); }; } // namespace panda::tooling::ecmascript -#endif +#endif // ECMASCRIPT_TOOLING_JS_PT_EXTRACTOR_H diff --git a/ecmascript/tooling/protocol_handler.cpp b/ecmascript/tooling/protocol_handler.cpp index cf13ea6ee..61f80835e 100644 --- a/ecmascript/tooling/protocol_handler.cpp +++ b/ecmascript/tooling/protocol_handler.cpp @@ -43,6 +43,7 @@ void ProtocolHandler::RunIfWaitingForDebugger() void ProtocolHandler::ProcessCommand(const CString &msg) { LOG(DEBUG, DEBUGGER) << "ProtocolHandler::ProcessCommand: " << msg; + [[maybe_unused]] LocalScope scope(vm_); Local exception = DebuggerApi::GetException(vm_); if (!exception->IsHole()) { DebuggerApi::ClearException(vm_); diff --git a/ecmascript/tooling/test/utils/test_extractor.cpp b/ecmascript/tooling/test/utils/test_extractor.cpp index 77a4198a6..5e1a9027f 100644 --- a/ecmascript/tooling/test/utils/test_extractor.cpp +++ b/ecmascript/tooling/test/utils/test_extractor.cpp @@ -39,19 +39,6 @@ std::pair TestExtractor::GetBreakpointAddress(const SourceLo return {retId, retOffset}; } -std::vector TestExtractor::GetLocalVariableInfo(EntityId methodId, size_t offset) -{ - const std::vector &variables = GetLocalVariableTable(methodId); - std::vector result; - - for (const auto &variable : variables) { - if (variable.start_offset <= offset && offset <= variable.end_offset) { - result.push_back(variable); - } - } - return result; -} - SourceLocation TestExtractor::GetSourceLocation(EntityId methodId, uint32_t bytecodeOffset) { SourceLocation location {GetSourceFile(methodId), 0, 0}; diff --git a/ecmascript/tooling/test/utils/test_extractor.h b/ecmascript/tooling/test/utils/test_extractor.h index 6b934e7ef..eb32ab190 100644 --- a/ecmascript/tooling/test/utils/test_extractor.h +++ b/ecmascript/tooling/test/utils/test_extractor.h @@ -17,12 +17,12 @@ #define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_EXTRACTOR_H #include "ecmascript/mem/c_string.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/js_pt_extractor.h" namespace panda::tooling::ecmascript::test { using EntityId = panda_file::File::EntityId; using panda::ecmascript::CString; -using panda::tooling::ecmascript::PtJSExtractor; +using panda::tooling::ecmascript::JSPtExtractor; // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) struct SourceLocation { @@ -41,15 +41,13 @@ struct SourceLocation { } }; -class TestExtractor : public PtJSExtractor { +class TestExtractor : public JSPtExtractor { public: - explicit TestExtractor(const panda_file::File *pandaFileData) : PtJSExtractor(pandaFileData) {} + explicit TestExtractor(const panda_file::File *pandaFileData) : JSPtExtractor(pandaFileData) {} ~TestExtractor() = default; std::pair GetBreakpointAddress(const SourceLocation &sourceLocation); - std::vector GetLocalVariableInfo(EntityId methodId, size_t offset); - SourceLocation GetSourceLocation(EntityId methodId, uint32_t bytecodeOffset); }; } // namespace panda::tooling::ecmascript::test diff --git a/ecmascript/tooling/test/utils/test_util.cpp b/ecmascript/tooling/test/utils/test_util.cpp index f096a1902..e5865fdae 100644 --- a/ecmascript/tooling/test/utils/test_util.cpp +++ b/ecmascript/tooling/test/utils/test_util.cpp @@ -27,38 +27,6 @@ bool TestUtil::suspended_ = false; PtThread TestUtil::lastEventThread_ = PtThread::NONE; PtLocation TestUtil::lastEventLocation_("", EntityId(0), 0); -std::vector TestUtil::GetVariables(JSMethod *method, uint32_t offset) -{ - auto methodId = method->GetFileId(); - auto pandaFile = method->GetPandaFile()->GetFilename().c_str(); - PtLocation location(pandaFile, methodId, offset); - return GetVariables(location); -} - -std::vector TestUtil::GetVariables(PtLocation location) -{ - std::unique_ptr uFile = panda_file::File::Open(location.GetPandaFile()); - const panda_file::File *pf = uFile.get(); - if (pf == nullptr) { - return {}; - } - - TestExtractor extractor(pf); - return extractor.GetLocalVariableInfo(location.GetMethodId(), location.GetBytecodeOffset()); -} - -int32_t TestUtil::GetValueRegister(JSMethod *method, const char *varName) -{ - auto variables = TestUtil::GetVariables(method, 0); - for (const auto &var : variables) { - if (var.name == varName) { - return var.reg_number; - } - } - - return -1; -} - std::ostream &operator<<(std::ostream &out, DebugEvent value) { const char *s = nullptr; diff --git a/ecmascript/tooling/test/utils/test_util.h b/ecmascript/tooling/test/utils/test_util.h index cf385850d..7c42b2743 100644 --- a/ecmascript/tooling/test/utils/test_util.h +++ b/ecmascript/tooling/test/utils/test_util.h @@ -146,12 +146,6 @@ public: return extractor.GetSourceLocation(location.GetMethodId(), location.GetBytecodeOffset()); } - static std::vector GetVariables(JSMethod *method, uint32_t offset); - - static std::vector GetVariables(PtLocation location); - - static int32_t GetValueRegister(JSMethod *method, const char *varName); - static bool SuspendUntilContinue(DebugEvent reason, PtThread thread, PtLocation location) { { -- Gitee