mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 08:03:29 +00:00
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 <wengchangcheng@huawei.com> Change-Id: Id64d718aa9360afd53398ee729714c859bd61768
This commit is contained in:
parent
6334759dfc
commit
5119c012f8
1
BUILD.gn
1
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",
|
||||
|
@ -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('?');
|
||||
|
@ -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 = "";
|
||||
|
@ -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<JSMethod>(nullptr, nullptr, panda_file::File::EntityId(0), panda_file::File::EntityId(0),
|
||||
accessFlags, numArgs, nullptr);
|
||||
auto method = chunk_.New<JSMethod>(nullptr, panda_file::File::EntityId(0), panda_file::File::EntityId(0),
|
||||
accessFlags, numArgs);
|
||||
method->SetNativePointer(const_cast<void *>(func));
|
||||
method->SetNativeBit(true);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -61,9 +61,8 @@ public:
|
||||
return static_cast<JSMethod *>(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;
|
||||
|
326
ecmascript/jspandafile/debug_info_extractor.cpp
Normal file
326
ecmascript/jspandafile/debug_info_extractor.cpp
Normal file
@ -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<Opcode>(*program_);
|
||||
++program_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
return opcode;
|
||||
}
|
||||
|
||||
int32_t ReadRegisterNumber()
|
||||
{
|
||||
auto [regiserNumber, n, isFull] = leb128::DecodeSigned<int32_t>(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<uint8_t>(opcode) >= LineNumberProgramItem::OPCODE_BASE);
|
||||
|
||||
auto adjustOpcode = static_cast<uint8_t>(static_cast<uint8_t>(opcode) - LineNumberProgramItem::OPCODE_BASE);
|
||||
auto pcOffset = static_cast<uint32_t>(adjustOpcode / LineNumberProgramItem::LINE_RANGE);
|
||||
int32_t lineOffset =
|
||||
static_cast<int32_t>(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<panda_file::File::EntityId> DebugInfoExtractor::GetMethodIdList() const
|
||||
{
|
||||
std::vector<panda_file::File::EntityId> list;
|
||||
|
||||
for (const auto &method : methods_) {
|
||||
list.push_back(panda_file::File::EntityId(method.first));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
} // namespace panda::ecmascript
|
87
ecmascript/jspandafile/debug_info_extractor.h
Normal file
87
ecmascript/jspandafile/debug_info_extractor.h
Normal file
@ -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 <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#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<LineTableEntry>;
|
||||
using ColumnNumberTable = std::vector<ColumnTableEntry>;
|
||||
|
||||
/*
|
||||
* 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<std::string, int32_t>;
|
||||
|
||||
// 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<panda_file::File::EntityId> 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<uint32_t, MethodDebugInfo> methods_;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
#endif // ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H
|
@ -37,15 +37,6 @@ JSPandaFile::~JSPandaFile()
|
||||
}
|
||||
}
|
||||
|
||||
tooling::ecmascript::PtJSExtractor *JSPandaFile::GetOrCreatePtJSExtractor()
|
||||
{
|
||||
if (ptJSExtractor_) {
|
||||
return ptJSExtractor_.get();
|
||||
}
|
||||
ptJSExtractor_ = std::make_unique<tooling::ecmascript::PtJSExtractor>(pf_);
|
||||
return ptJSExtractor_.get();
|
||||
}
|
||||
|
||||
uint32_t JSPandaFile::GetOrInsertConstantPool(ConstPoolType type, uint32_t offset)
|
||||
{
|
||||
auto it = constpoolMap_.find(offset);
|
||||
|
@ -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<uint32_t, JSMethod *> methodMap_;
|
||||
const panda_file::File *pf_ {nullptr};
|
||||
std::unique_ptr<tooling::ecmascript::PtJSExtractor> ptJSExtractor_;
|
||||
std::string desc_;
|
||||
bool isModule_ {false};
|
||||
};
|
||||
|
@ -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<tooling::ecmascript::JSPtExtractor>(jsPandaFile->GetPandaFile());
|
||||
tooling::ecmascript::JSPtExtractor *extractor = extractorPtr.get();
|
||||
extractors_[jsPandaFile] = std::move(extractorPtr);
|
||||
return extractor;
|
||||
}
|
||||
return const_cast<JSPandaFile *>(jsPandaFile)->GetOrCreatePtJSExtractor();
|
||||
|
||||
return iter->second.get();
|
||||
}
|
||||
|
||||
const JSPandaFile *JSPandaFileManager::GenerateJSPandaFile(const panda_file::File *pf, const std::string &desc)
|
||||
|
@ -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<const JSPandaFile *, uint32_t> loadedJSPandaFiles_;
|
||||
std::unordered_map<const JSPandaFile *, std::unique_ptr<tooling::ecmascript::JSPtExtractor>> extractors_;
|
||||
|
||||
friend class JSPandaFile;
|
||||
};
|
||||
|
@ -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,30 +88,33 @@ void PandaFileTranslator::TranslateClasses(JSPandaFile *jsPandaFile, const CStri
|
||||
|
||||
JSHandle<Program> PandaFileTranslator::GenerateProgram(EcmaVM *vm, const JSPandaFile *jsPandaFile)
|
||||
{
|
||||
JSThread *thread = vm->GetJSThread();
|
||||
EcmaHandleScope handleScope(thread);
|
||||
|
||||
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
|
||||
ObjectFactory *factory = vm->GetFactory();
|
||||
JSHandle<Program> program = factory->NewProgram();
|
||||
|
||||
uint32_t mainMethodIndex = jsPandaFile->GetMainMethodIndex();
|
||||
auto method = jsPandaFile->FindMethods(mainMethodIndex);
|
||||
ASSERT(method != nullptr);
|
||||
JSHandle<JSHClass> dynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithProto());
|
||||
JSHandle<JSFunction> mainFunc =
|
||||
factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::BASE_CONSTRUCTOR);
|
||||
{
|
||||
JSThread *thread = vm->GetJSThread();
|
||||
EcmaHandleScope handleScope(thread);
|
||||
|
||||
program->SetMainFunction(thread, mainFunc.GetTaggedValue());
|
||||
JSHandle<GlobalEnv> 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<JSHClass> dynclass = JSHandle<JSHClass>::Cast(env->GetFunctionClassWithProto());
|
||||
JSHandle<JSFunction> mainFunc =
|
||||
factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::BASE_CONSTRUCTOR);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
mainFunc->SetConstantPool(thread, constpool);
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
|
@ -31,12 +31,13 @@ JSTaggedValue ScopeInfoExtractor::GenerateScopeInfo(JSThread *thread, uint16_t s
|
||||
|
||||
auto buffer = ecmaVm->GetNativeAreaAllocator()->New<struct ScopeDebugInfo>();
|
||||
auto scopeDebugInfo = static_cast<struct ScopeDebugInfo *>(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<JSNativePointer> pointer = factory->NewJSNativePointer(
|
||||
|
@ -19,6 +19,10 @@
|
||||
#include "ecmascript/js_tagged_value-inl.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
struct ScopeDebugInfo {
|
||||
std::unordered_map<std::string, uint32_t> scopeInfo;
|
||||
};
|
||||
|
||||
class ScopeInfoExtractor {
|
||||
public:
|
||||
explicit ScopeInfoExtractor() = default;
|
||||
|
@ -19,15 +19,6 @@
|
||||
#include "ecmascript/js_object.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
struct ScopeInfo {
|
||||
uint32_t slot;
|
||||
CString name;
|
||||
};
|
||||
|
||||
struct ScopeDebugInfo {
|
||||
std::vector<ScopeInfo> scopeInfo;
|
||||
};
|
||||
|
||||
class LexicalEnv : public TaggedArray {
|
||||
public:
|
||||
static constexpr uint32_t PARENT_ENV_INDEX = 0;
|
||||
|
@ -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") {
|
||||
|
@ -60,7 +60,7 @@ void JSBackend::NotifyPaused(std::optional<PtLocation> location, PauseReason rea
|
||||
CVector<CString> 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<Error> JSBackend::GetPossibleBreakpoints(Location *start, [[maybe_unused]] Location *end,
|
||||
CVector<std::unique_ptr<BreakLocation>> *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<Error> JSBackend::GetPossibleBreakpoints(Location *start, [[maybe_
|
||||
std::optional<Error> JSBackend::SetBreakpointByUrl(const CString &url, size_t lineNumber,
|
||||
size_t columnNumber, CString *out_id, CVector<std::unique_ptr<Location>> *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<Error> JSBackend::SetBreakpointByUrl(const CString &url, size_t li
|
||||
|
||||
std::optional<Error> 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<Error> JSBackend::Resume()
|
||||
std::optional<Error> 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<Error> JSBackend::StepInto()
|
||||
std::optional<Error> 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<Error> JSBackend::StepOver()
|
||||
std::optional<Error> 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<Error> 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<Error> 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<Error> 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<PtJSExtractor>(file);
|
||||
PtJSExtractor *res = extractor.get();
|
||||
auto extractor = std::make_unique<JSPtExtractor>(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<Scope> JSBackend::GetLocalScopeChain(const InterpretedFrameHandl
|
||||
.SetDescription(RemoteObject::ObjectDescription);
|
||||
propertiesPair_[curObjectId_++] = Global<JSValueRef>(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<Scope> JSBackend::GetLocalScopeChain(const InterpretedFrameHandl
|
||||
Local<JSValueRef> name = JSValueRef::Undefined(ecmaVm_);
|
||||
Local<JSValueRef> 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<JSValueRef>(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<Scope> JSBackend::GetLocalScopeChain(const InterpretedFrameHandl
|
||||
}
|
||||
}
|
||||
|
||||
const panda_file::LineNumberTable &lines = extractor->GetLineNumberTable(methodId);
|
||||
auto lines = extractor->GetLineNumberTable(methodId);
|
||||
std::unique_ptr<Location> startLoc = std::make_unique<Location>();
|
||||
std::unique_ptr<Location> endLoc = std::make_unique<Location>();
|
||||
auto scriptFunc = [&startLoc, &endLoc, lines](PtScript *script) -> bool {
|
||||
|
@ -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<Scope> GetLocalScopeChain(const InterpretedFrameHandler *frameHandler,
|
||||
std::unique_ptr<RemoteObject> *thisObj);
|
||||
@ -137,13 +137,13 @@ private:
|
||||
const EcmaVM *ecmaVm_ {nullptr};
|
||||
std::unique_ptr<JSPtHooks> hooks_ {nullptr};
|
||||
JSDebugger *debugger_ {nullptr};
|
||||
CMap<const std::string, std::unique_ptr<PtJSExtractor>> extractors_ {};
|
||||
CMap<const std::string, std::unique_ptr<JSPtExtractor>> extractors_ {};
|
||||
CMap<CString, std::unique_ptr<PtScript>> scripts_ {};
|
||||
CMap<uint32_t, Global<JSValueRef>> propertiesPair_ {};
|
||||
uint32_t curObjectId_ {0};
|
||||
bool pauseOnException_ {false};
|
||||
bool pauseOnNextByteCode_ {false};
|
||||
std::unique_ptr<PtJSExtractor::SingleStepper> singleStepper_ {nullptr};
|
||||
std::unique_ptr<JSPtExtractor::SingleStepper> singleStepper_ {nullptr};
|
||||
|
||||
friend class JSPtHooks;
|
||||
};
|
||||
|
@ -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"
|
||||
|
@ -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<ScopeDebugInfo *>(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<JSValueRef> DebuggerApi::GetLexicalValueInfo(const EcmaVM *ecmaVm, const CString &name)
|
||||
Local<JSValueRef> DebuggerApi::GetLexicalValueInfo(const EcmaVM *ecmaVm, const std::string &name)
|
||||
{
|
||||
JSThread *thread = ecmaVm->GetJSThread();
|
||||
JSTaggedValue curEnv = thread->GetCurrentLexenv();
|
||||
@ -256,14 +256,14 @@ Local<JSValueRef> DebuggerApi::GetLexicalValueInfo(const EcmaVM *ecmaVm, const C
|
||||
}
|
||||
void *pointer = JSNativePointer::Cast(lexicalEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer();
|
||||
ScopeDebugInfo *scopeDebugInfo = static_cast<ScopeDebugInfo *>(pointer);
|
||||
for (const auto &info : scopeDebugInfo->scopeInfo) {
|
||||
if (info.name == name) {
|
||||
uint16_t slot = info.slot;
|
||||
JSTaggedValue value = lexicalEnv->GetProperties(slot);
|
||||
JSHandle<JSTaggedValue> handledValue(thread, value);
|
||||
return JSNApiHelper::ToLocal<JSValueRef>(handledValue);
|
||||
}
|
||||
auto iter = scopeDebugInfo->scopeInfo.find(name);
|
||||
if (iter == scopeDebugInfo->scopeInfo.end()) {
|
||||
continue;
|
||||
}
|
||||
uint32_t slot = iter->second;
|
||||
JSTaggedValue value = lexicalEnv->GetProperties(slot);
|
||||
JSHandle<JSTaggedValue> handledValue(thread, value);
|
||||
return JSNApiHelper::ToLocal<JSValueRef>(handledValue);
|
||||
}
|
||||
JSHandle<JSTaggedValue> handledValue(thread, JSTaggedValue::Hole());
|
||||
return JSNApiHelper::ToLocal<JSValueRef>(handledValue);
|
||||
|
@ -97,8 +97,8 @@ public:
|
||||
// ScopeInfo
|
||||
static Local<JSValueRef> GetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t slot);
|
||||
static void SetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t slot, Local<JSValueRef> value);
|
||||
static bool EvaluateLexicalValue(const EcmaVM *ecmaVm, const CString &name, int32_t &level, uint32_t &slot);
|
||||
static Local<JSValueRef> 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<JSValueRef> GetLexicalValueInfo(const EcmaVM *ecmaVm, const std::string &name);
|
||||
};
|
||||
} // namespace panda::tooling::ecmascript
|
||||
|
||||
|
@ -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::SingleStepper> PtJSExtractor::GetStepIntoStepper(const EcmaVM *ecmaVm)
|
||||
std::unique_ptr<JSPtExtractor::SingleStepper> JSPtExtractor::GetStepIntoStepper(const EcmaVM *ecmaVm)
|
||||
{
|
||||
return GetStepper(ecmaVm, SingleStepper::Type::INTO);
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJSExtractor::SingleStepper> PtJSExtractor::GetStepOverStepper(const EcmaVM *ecmaVm)
|
||||
std::unique_ptr<JSPtExtractor::SingleStepper> JSPtExtractor::GetStepOverStepper(const EcmaVM *ecmaVm)
|
||||
{
|
||||
return GetStepper(ecmaVm, SingleStepper::Type::OVER);
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJSExtractor::SingleStepper> PtJSExtractor::GetStepOutStepper(const EcmaVM *ecmaVm)
|
||||
std::unique_ptr<JSPtExtractor::SingleStepper> JSPtExtractor::GetStepOutStepper(const EcmaVM *ecmaVm)
|
||||
{
|
||||
return GetStepper(ecmaVm, SingleStepper::Type::OUT);
|
||||
}
|
||||
|
||||
CList<PtStepRange> PtJSExtractor::GetStepRanges(File::EntityId methodId, uint32_t offset)
|
||||
CList<PtStepRange> JSPtExtractor::GetStepRanges(File::EntityId methodId, uint32_t offset)
|
||||
{
|
||||
CList<PtStepRange> ranges {};
|
||||
auto table = GetLineNumberTable(methodId);
|
||||
@ -103,7 +103,7 @@ CList<PtStepRange> PtJSExtractor::GetStepRanges(File::EntityId methodId, uint32_
|
||||
return ranges;
|
||||
}
|
||||
|
||||
std::unique_ptr<PtJSExtractor::SingleStepper> PtJSExtractor::GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type)
|
||||
std::unique_ptr<JSPtExtractor::SingleStepper> JSPtExtractor::GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type)
|
||||
{
|
||||
JSMethod *method = DebuggerApi::GetMethod(ecmaVm);
|
||||
ASSERT(method != nullptr);
|
@ -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<class Callback>
|
||||
bool MatchWithLocation(const Callback &cb, size_t line, size_t column)
|
||||
@ -122,10 +122,10 @@ public:
|
||||
std::unique_ptr<SingleStepper> GetStepOutStepper(const EcmaVM *ecmaVm);
|
||||
|
||||
private:
|
||||
NO_COPY_SEMANTIC(PtJSExtractor);
|
||||
NO_MOVE_SEMANTIC(PtJSExtractor);
|
||||
NO_COPY_SEMANTIC(JSPtExtractor);
|
||||
NO_MOVE_SEMANTIC(JSPtExtractor);
|
||||
CList<PtStepRange> GetStepRanges(File::EntityId methodId, uint32_t offset);
|
||||
std::unique_ptr<SingleStepper> GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type);
|
||||
};
|
||||
} // namespace panda::tooling::ecmascript
|
||||
#endif
|
||||
#endif // ECMASCRIPT_TOOLING_JS_PT_EXTRACTOR_H
|
@ -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<JSValueRef> exception = DebuggerApi::GetException(vm_);
|
||||
if (!exception->IsHole()) {
|
||||
DebuggerApi::ClearException(vm_);
|
||||
|
@ -39,19 +39,6 @@ std::pair<EntityId, uint32_t> TestExtractor::GetBreakpointAddress(const SourceLo
|
||||
return {retId, retOffset};
|
||||
}
|
||||
|
||||
std::vector<panda_file::LocalVariableInfo> TestExtractor::GetLocalVariableInfo(EntityId methodId, size_t offset)
|
||||
{
|
||||
const std::vector<panda_file::LocalVariableInfo> &variables = GetLocalVariableTable(methodId);
|
||||
std::vector<panda_file::LocalVariableInfo> 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};
|
||||
|
@ -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<EntityId, uint32_t> GetBreakpointAddress(const SourceLocation &sourceLocation);
|
||||
|
||||
std::vector<panda_file::LocalVariableInfo> GetLocalVariableInfo(EntityId methodId, size_t offset);
|
||||
|
||||
SourceLocation GetSourceLocation(EntityId methodId, uint32_t bytecodeOffset);
|
||||
};
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
@ -27,38 +27,6 @@ bool TestUtil::suspended_ = false;
|
||||
PtThread TestUtil::lastEventThread_ = PtThread::NONE;
|
||||
PtLocation TestUtil::lastEventLocation_("", EntityId(0), 0);
|
||||
|
||||
std::vector<panda_file::LocalVariableInfo> 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<panda_file::LocalVariableInfo> TestUtil::GetVariables(PtLocation location)
|
||||
{
|
||||
std::unique_ptr<const panda_file::File> 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;
|
||||
|
@ -146,12 +146,6 @@ public:
|
||||
return extractor.GetSourceLocation(location.GetMethodId(), location.GetBytecodeOffset());
|
||||
}
|
||||
|
||||
static std::vector<panda_file::LocalVariableInfo> GetVariables(JSMethod *method, uint32_t offset);
|
||||
|
||||
static std::vector<panda_file::LocalVariableInfo> GetVariables(PtLocation location);
|
||||
|
||||
static int32_t GetValueRegister(JSMethod *method, const char *varName);
|
||||
|
||||
static bool SuspendUntilContinue(DebugEvent reason, PtThread thread, PtLocation location)
|
||||
{
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user