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:
wengchangcheng 2022-03-24 16:43:08 +08:00
parent 6334759dfc
commit 5119c012f8
29 changed files with 552 additions and 213 deletions

View File

@ -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",

View File

@ -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('?');

View File

@ -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 = "";

View File

@ -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);

View File

@ -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;
}

View File

@ -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;

View 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

View 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

View File

@ -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);

View File

@ -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};
};

View File

@ -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)

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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(

View File

@ -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;

View File

@ -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;

View File

@ -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") {

View File

@ -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 {

View File

@ -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;
};

View File

@ -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"

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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_);

View File

@ -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};

View File

@ -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

View File

@ -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;

View File

@ -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)
{
{