mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-23 18:20:04 +00:00
modify debugger events and api test
Signed-off-by: wengchangcheng <wengchangcheng@huawei.com> Change-Id: I2b63f2d9af7eba0b5319e7ed459bb48e665f13d8
This commit is contained in:
parent
a19ee9c8c6
commit
46307fb5d8
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,3 +12,4 @@ tags
|
||||
.byebug_history
|
||||
.cache
|
||||
*.swp
|
||||
*.abc
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "ecmascript/js_tagged_value.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "ecmascript/tooling/js_pt_lang_ext.h"
|
||||
#include "include/tooling/pt_lang_extension.h"
|
||||
|
||||
namespace panda {
|
||||
@ -71,7 +72,7 @@ std::unique_ptr<ClassLinkerExtension> EcmaLanguageContext::CreateClassLinkerExte
|
||||
|
||||
PandaUniquePtr<tooling::PtLangExt> EcmaLanguageContext::CreatePtLangExt() const
|
||||
{
|
||||
return PandaUniquePtr<tooling::PtLangExt>();
|
||||
return MakePandaUnique<tooling::ecmascript::JSPtLangExt>();
|
||||
}
|
||||
|
||||
void EcmaLanguageContext::ThrowException(ManagedThread *thread, const uint8_t *mutf8_name,
|
||||
|
@ -193,7 +193,7 @@ bool EcmaVM::Initialize()
|
||||
moduleManager_ = new ModuleManager(this);
|
||||
InitializeFinish();
|
||||
notificationManager_->VmStartEvent();
|
||||
notificationManager_->VmInitializationEvent(0);
|
||||
notificationManager_->VmInitializationEvent(thread_->GetThreadId());
|
||||
Platform::GetCurrentPlatform()->PostTask(std::make_unique<TrimNewSpaceLimitTask>(heap_));
|
||||
return true;
|
||||
}
|
||||
@ -258,6 +258,7 @@ bool EcmaVM::InitializeFinish()
|
||||
vmInitialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
EcmaVM::~EcmaVM()
|
||||
{
|
||||
vmInitialized_ = false;
|
||||
@ -492,9 +493,6 @@ void EcmaVM::AddPandaFile(const panda_file::File *pf, bool isModule)
|
||||
{
|
||||
ASSERT(pf != nullptr);
|
||||
pandaFileWithProgram_.push_back(std::make_tuple(nullptr, pf, isModule));
|
||||
|
||||
// for debugger
|
||||
notificationManager_->LoadModuleEvent(pf->GetFilename());
|
||||
}
|
||||
|
||||
void EcmaVM::SetProgram(Program *program, const panda_file::File *pf)
|
||||
@ -503,6 +501,8 @@ void EcmaVM::SetProgram(Program *program, const panda_file::File *pf)
|
||||
[pf](auto entry) { return std::get<1>(entry) == pf; });
|
||||
ASSERT(it != pandaFileWithProgram_.end());
|
||||
std::get<0>(*it) = program;
|
||||
// for debugger
|
||||
notificationManager_->LoadModuleEvent(pf->GetFilename());
|
||||
}
|
||||
|
||||
bool EcmaVM::IsFrameworkPandaFile(std::string_view filename) const
|
||||
|
@ -93,6 +93,14 @@ namespace panda::ecmascript {
|
||||
goto *dispatchTable[EcmaOpcode::LAST_OPCODE]; \
|
||||
} while (false)
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define INTERPRETER_HANDLE_RETURN() \
|
||||
do { \
|
||||
thread->GetEcmaVM()->GetNotificationManager()->MethodExitEvent(thread, method); \
|
||||
size_t jumpSize = GetJumpSizeAfterCall(pc); \
|
||||
DISPATCH_OFFSET(jumpSize); \
|
||||
} while (false)
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define CHECK_SWITCH_TO_DEBUGGER_TABLE() \
|
||||
if (Runtime::GetCurrent()->IsDebugMode()) { \
|
||||
@ -228,8 +236,8 @@ JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *thread, const CallParams&
|
||||
JSTaggedType *sp = const_cast<JSTaggedType *>(thread->GetCurrentSPFrame());
|
||||
JSTaggedType *fixedSp = FixSpOnEntry(thread);
|
||||
|
||||
JSMethod *methodToCall = params.callTarget->GetCallTarget();
|
||||
ASSERT(methodToCall->GetNumVregs() == 0);
|
||||
JSMethod *method = params.callTarget->GetCallTarget();
|
||||
ASSERT(method->GetNumVregs() == 0);
|
||||
uint32_t numActualArgs = params.argc + RESERVED_CALL_ARGCOUNT;
|
||||
// Tags and values of thread, new_tgt and argv_length are put into frames too for native frames
|
||||
// NOLINTNEXTLINE(hicpp-signed-bitwise)
|
||||
@ -261,7 +269,7 @@ JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *thread, const CallParams&
|
||||
thread->CheckSafepoint();
|
||||
LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call.";
|
||||
JSTaggedValue tagged =
|
||||
reinterpret_cast<EcmaEntrypoint>(const_cast<void *>(methodToCall->GetNativePointer()))(&ecmaRuntimeCallInfo);
|
||||
reinterpret_cast<EcmaEntrypoint>(const_cast<void *>(method->GetNativePointer()))(&ecmaRuntimeCallInfo);
|
||||
LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call.";
|
||||
thread->SetCurrentSPFrame(sp);
|
||||
#if ECMASCRIPT_ENABLE_ACTIVE_CPUPROFILER
|
||||
@ -380,7 +388,9 @@ JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, const CallParams& param
|
||||
thread->CheckSafepoint();
|
||||
LOG(DEBUG, INTERPRETER) << "break Entry: Runtime Call " << std::hex << reinterpret_cast<uintptr_t>(newSp) << " "
|
||||
<< std::hex << reinterpret_cast<uintptr_t>(pc);
|
||||
thread->GetEcmaVM()->GetNotificationManager()->MethodEntryEvent(thread, method);
|
||||
EcmaInterpreter::RunInternal(thread, ConstantPool::Cast(constpool.GetTaggedObject()), pc, newSp);
|
||||
thread->GetEcmaVM()->GetNotificationManager()->MethodExitEvent(thread, method);
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
const JSTaggedValue resAcc = state->acc;
|
||||
@ -446,7 +456,9 @@ JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSH
|
||||
state->env = env;
|
||||
// execute interpreter
|
||||
thread->SetCurrentSPFrame(newSp);
|
||||
thread->GetEcmaVM()->GetNotificationManager()->MethodEntryEvent(thread, method);
|
||||
EcmaInterpreter::RunInternal(thread, ConstantPool::Cast(constpool.GetTaggedObject()), resumePc, newSp);
|
||||
thread->GetEcmaVM()->GetNotificationManager()->MethodExitEvent(thread, method);
|
||||
|
||||
JSTaggedValue res = state->acc;
|
||||
// pop frame
|
||||
@ -778,9 +790,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
INTERPRETER_GOTO_EXCEPTION_HANDLER();
|
||||
}
|
||||
ECMAObject *thisFunc = ECMAObject::Cast(func.GetTaggedObject());
|
||||
JSMethod *methodToCall = thisFunc->GetCallTarget();
|
||||
if (methodToCall->IsNative()) {
|
||||
ASSERT(methodToCall->GetNumVregs() == 0);
|
||||
JSMethod *method = thisFunc->GetCallTarget();
|
||||
if (method->IsNative()) {
|
||||
ASSERT(method->GetNumVregs() == 0);
|
||||
// Tags and values of thread, new_tgt and argv_length are put into frames too for native frames
|
||||
// NOLINTNEXTLINE(hicpp-signed-bitwise)
|
||||
size_t frameSize = FRAME_STATE_SIZE + actualNumArgs + NUM_MANDATORY_JSFUNC_ARGS;
|
||||
@ -853,16 +865,16 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
state->function = func;
|
||||
thread->SetCurrentSPFrame(newSp);
|
||||
LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call.";
|
||||
thread->GetEcmaVM()->GetNotificationManager()->MethodEntryEvent(thread, method);
|
||||
JSTaggedValue retValue = reinterpret_cast<EcmaEntrypoint>(
|
||||
const_cast<void *>(methodToCall->GetNativePointer()))(&ecmaRuntimeCallInfo);
|
||||
const_cast<void *>(method->GetNativePointer()))(&ecmaRuntimeCallInfo);
|
||||
if (UNLIKELY(thread->HasPendingException())) {
|
||||
INTERPRETER_GOTO_EXCEPTION_HANDLER();
|
||||
}
|
||||
LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call.";
|
||||
thread->SetCurrentSPFrame(sp);
|
||||
SET_ACC(retValue);
|
||||
size_t jumpSize = GetJumpSizeAfterCall(pc);
|
||||
DISPATCH_OFFSET(jumpSize);
|
||||
INTERPRETER_HANDLE_RETURN();
|
||||
} else {
|
||||
if (JSFunction::Cast(thisFunc)->IsClassConstructor()) {
|
||||
{
|
||||
@ -875,10 +887,10 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
}
|
||||
SAVE_PC();
|
||||
JSTaggedType *newSp = nullptr;
|
||||
uint32_t callType = methodToCall->GetCallType();
|
||||
uint32_t callType = method->GetCallType();
|
||||
if (callType == NORMAL_CALL_TYPE) { // fast path
|
||||
uint32_t numVregs = methodToCall->GetNumVregs();
|
||||
uint32_t numDeclaredArgs = methodToCall->GetNumArgs();
|
||||
uint32_t numVregs = method->GetNumVregs();
|
||||
uint32_t numDeclaredArgs = method->GetNumArgs();
|
||||
uint32_t copyArgs = std::min(numDeclaredArgs, actualNumArgs);
|
||||
size_t frameSize = FRAME_STATE_SIZE + numVregs + numDeclaredArgs;
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
@ -924,8 +936,8 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
bool haveNewTarget = callType & HAVE_NEWTARGET_BIT;
|
||||
bool haveExtra = callType & HAVE_EXTRA_BIT;
|
||||
bool haveFunc = callType & HAVE_FUNC_BIT;
|
||||
uint32_t numVregs = methodToCall->GetNumVregs();
|
||||
uint32_t numDeclaredArgs = methodToCall->GetNumArgs();
|
||||
uint32_t numVregs = method->GetNumVregs();
|
||||
uint32_t numDeclaredArgs = method->GetNumArgs();
|
||||
uint32_t copyArgs = haveFunc + haveNewTarget + haveThis;
|
||||
size_t frameSize = FRAME_STATE_SIZE + numVregs;
|
||||
if (haveExtra) {
|
||||
@ -995,7 +1007,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
InterpretedFrame *state = GET_FRAME(newSp);
|
||||
state->base.prev = sp;
|
||||
state->base.frameType = static_cast<uintptr_t>(FrameType::INTERPRETER_FRAME);
|
||||
state->pc = pc = JSMethod::Cast(methodToCall)->GetBytecodeArray();
|
||||
state->pc = pc = JSMethod::Cast(method)->GetBytecodeArray();
|
||||
state->sp = sp = newSp;
|
||||
state->function = func;
|
||||
state->acc = JSTaggedValue::Hole();
|
||||
@ -1008,6 +1020,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
thread->SetCurrentSPFrame(newSp);
|
||||
LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call " << std::hex << reinterpret_cast<uintptr_t>(sp) << " "
|
||||
<< std::hex << reinterpret_cast<uintptr_t>(pc);
|
||||
thread->GetEcmaVM()->GetNotificationManager()->MethodEntryEvent(thread, method);
|
||||
DISPATCH_OFFSET(0);
|
||||
}
|
||||
}
|
||||
@ -1034,8 +1047,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
|
||||
constpool = ConstantPool::Cast(prevState->constpool.GetTaggedObject());
|
||||
|
||||
size_t jumpSize = GetJumpSizeAfterCall(pc);
|
||||
DISPATCH_OFFSET(jumpSize);
|
||||
INTERPRETER_HANDLE_RETURN();
|
||||
}
|
||||
HANDLE_OPCODE(HANDLE_RETURNUNDEFINED_PREF) {
|
||||
LOG_INST() << "return.undefined";
|
||||
@ -1060,8 +1072,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
constpool = ConstantPool::Cast(prevState->constpool.GetTaggedObject());
|
||||
|
||||
acc = JSTaggedValue::Undefined();
|
||||
size_t jumpSize = GetJumpSizeAfterCall(pc);
|
||||
DISPATCH_OFFSET(jumpSize);
|
||||
INTERPRETER_HANDLE_RETURN();
|
||||
}
|
||||
HANDLE_OPCODE(HANDLE_LDNAN_PREF) {
|
||||
LOG_INST() << "intrinsics::ldnan";
|
||||
@ -2186,8 +2197,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool
|
||||
thread->SetCurrentSPFrame(sp);
|
||||
constpool = ConstantPool::Cast(prevState->constpool.GetTaggedObject());
|
||||
|
||||
size_t jumpSize = GetJumpSizeAfterCall(pc);
|
||||
DISPATCH_OFFSET(jumpSize);
|
||||
INTERPRETER_HANDLE_RETURN();
|
||||
}
|
||||
HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONAWAITUNCAUGHT_PREF_V8_V8) {
|
||||
uint16_t v0 = READ_INST_8_1();
|
||||
|
@ -30,17 +30,17 @@ CString JSMethod::ParseFunctionName() const
|
||||
|
||||
void JSMethod::SetCallTypeFromAnnotation()
|
||||
{
|
||||
const panda_file::File *panda_file_ = GetPandaFile();
|
||||
panda_file::File::EntityId field_id_ = GetFileId();
|
||||
panda_file::MethodDataAccessor mda(*panda_file_, field_id_);
|
||||
const panda_file::File *pandaFile = GetPandaFile();
|
||||
panda_file::File::EntityId fieldId = GetFileId();
|
||||
panda_file::MethodDataAccessor mda(*pandaFile, fieldId);
|
||||
mda.EnumerateAnnotations([&](panda_file::File::EntityId annotation_id) {
|
||||
panda_file::AnnotationDataAccessor ada(*panda_file_, annotation_id);
|
||||
auto *annotation_name = reinterpret_cast<const char *>(panda_file_->GetStringData(ada.GetClassId()).data);
|
||||
panda_file::AnnotationDataAccessor ada(*pandaFile, annotation_id);
|
||||
auto *annotation_name = reinterpret_cast<const char *>(pandaFile->GetStringData(ada.GetClassId()).data);
|
||||
if (::strcmp("L_ESCallTypeAnnotation;", annotation_name) == 0) {
|
||||
uint32_t elem_count = ada.GetCount();
|
||||
for (uint32_t i = 0; i < elem_count; i++) {
|
||||
panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
|
||||
auto *elem_name = reinterpret_cast<const char *>(panda_file_->GetStringData(adae.GetNameId()).data);
|
||||
auto *elem_name = reinterpret_cast<const char *>(pandaFile->GetStringData(adae.GetNameId()).data);
|
||||
if (::strcmp("callType", elem_name) == 0) {
|
||||
callType_ = adae.GetScalarValue().GetValue();
|
||||
}
|
||||
|
@ -13,8 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef LIBPANDABASE_ECMASCRIPT_MEM_C_CONTAINERS_H
|
||||
#define LIBPANDABASE_ECMASCRIPT_MEM_C_CONTAINERS_H
|
||||
#ifndef ECMASCRIPT_MEM_C_CONTAINERS_H
|
||||
#define ECMASCRIPT_MEM_C_CONTAINERS_H
|
||||
|
||||
#include <deque>
|
||||
#include <list>
|
||||
@ -60,4 +60,4 @@ template<class Key, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<
|
||||
using CUnorderedSet = std::unordered_set<Key, Hash, KeyEqual, CAddressAllocator<Key>>;
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
#endif // LIBPANDABASE_ECMASCRIPT_MEM_C_CONTAINERS_H
|
||||
#endif // ECMASCRIPT_MEM_C_CONTAINERS_H
|
||||
|
@ -50,6 +50,7 @@
|
||||
#include "ecmascript/mem/region.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "ecmascript/tagged_array.h"
|
||||
#include "include/runtime_notification.h"
|
||||
#include "libpandabase/os/library_loader.h"
|
||||
#include "utils/pandargs.h"
|
||||
|
||||
@ -178,6 +179,7 @@ EcmaVM *JSNApi::CreateJSVM(const RuntimeOption &option)
|
||||
|
||||
void JSNApi::DestroyJSVM(EcmaVM *ecmaVm)
|
||||
{
|
||||
ecmaVm->GetNotificationManager()->VmDeathEvent();
|
||||
auto runtime = Runtime::GetCurrent();
|
||||
if (runtime != nullptr) {
|
||||
PandaVM *mainVm = runtime->GetPandaVM();
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/js_function.h"
|
||||
#include "ecmascript/js_handle.h"
|
||||
#include "ecmascript/napi/include/jsnapi.h"
|
||||
#include "ecmascript/object_factory.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "include/runtime_options.h"
|
||||
@ -82,7 +83,8 @@ public:
|
||||
}
|
||||
|
||||
// If you want to call once create, you can refer to BuiltinsMathTest for detail.
|
||||
static void CreateEcmaVMWithScope(PandaVM *&instance, JSThread *&thread, EcmaHandleScope *&scope)
|
||||
static void CreateEcmaVMWithScope(PandaVM *&instance, JSThread *&thread, EcmaHandleScope *&scope,
|
||||
const char *libraryPath = nullptr)
|
||||
{
|
||||
JSRuntimeOptions options;
|
||||
options.SetShouldLoadBootPandaFiles(false);
|
||||
@ -91,6 +93,10 @@ public:
|
||||
options.SetRuntimeType("ecmascript");
|
||||
options.SetPreGcHeapVerifyEnabled(true);
|
||||
options.SetEnableForceGC(true);
|
||||
if (libraryPath != nullptr) {
|
||||
// for class Runtime to StartDebugger
|
||||
options.SetDebuggerLibraryPath(libraryPath);
|
||||
}
|
||||
static EcmaLanguageContext lcEcma;
|
||||
[[maybe_unused]] bool success = Runtime::Create(options, {&lcEcma});
|
||||
ASSERT_TRUE(success) << "Cannot create Runtime";
|
||||
@ -111,8 +117,7 @@ public:
|
||||
EcmaVM::Cast(instance)->SetEnableForceGC(false);
|
||||
auto thread = EcmaVM::Cast(instance)->GetJSThread();
|
||||
thread->ClearException();
|
||||
[[maybe_unused]] bool success = Runtime::Destroy();
|
||||
ASSERT_TRUE(success) << "Cannot destroy Runtime";
|
||||
JSNApi::DestroyJSVM(EcmaVM::Cast(instance));
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
#include "ecmascript/class_linker/program_object-inl.h"
|
||||
#include "ecmascript/js_thread.h"
|
||||
#include "runtime/tooling/pt_method_private.h"
|
||||
|
||||
namespace panda::tooling::ecmascript {
|
||||
using panda::ecmascript::Program;
|
||||
@ -75,40 +76,39 @@ void JSDebugger::BytecodePcChanged(ManagedThread *thread, Method *method, uint32
|
||||
|
||||
bool JSDebugger::HandleBreakpoint(const JSThread *thread, const JSMethod *method, uint32_t bcOffset)
|
||||
{
|
||||
if (!FindBreakpoint(method, bcOffset)) {
|
||||
if (hooks_ == nullptr || !FindBreakpoint(method, bcOffset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *pf = method->GetPandaFile();
|
||||
PtLocation location {pf->GetFilename().c_str(), method->GetFileId(), bcOffset};
|
||||
if (hooks_ != nullptr) {
|
||||
hooks_->Breakpoint(PtThread(thread->GetId()), location);
|
||||
}
|
||||
|
||||
hooks_->Breakpoint(PtThread(thread->GetId()), location);
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSDebugger::HandleExceptionThrowEvent(const JSThread *thread, const JSMethod *method, uint32_t bcOffset)
|
||||
{
|
||||
if (!thread->HasPendingException()) {
|
||||
if (hooks_ == nullptr || !thread->HasPendingException()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto *pf = method->GetPandaFile();
|
||||
PtLocation throwLocation {pf->GetFilename().c_str(), method->GetFileId(), bcOffset};
|
||||
|
||||
if (hooks_ != nullptr) {
|
||||
hooks_->Exception(PtThread(thread->GetId()), throwLocation, PtObject(), throwLocation);
|
||||
}
|
||||
hooks_->Exception(PtThread(thread->GetId()), throwLocation, PtObject(), throwLocation);
|
||||
}
|
||||
|
||||
bool JSDebugger::HandleStep(const JSThread *thread, const JSMethod *method, uint32_t bcOffset)
|
||||
{
|
||||
if (hooks_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *pf = method->GetPandaFile();
|
||||
PtLocation location {pf->GetFilename().c_str(), method->GetFileId(), bcOffset};
|
||||
if (hooks_ != nullptr) {
|
||||
hooks_->SingleStep(PtThread(thread->GetId()), location);
|
||||
}
|
||||
|
||||
hooks_->SingleStep(PtThread(thread->GetId()), location);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -155,4 +155,28 @@ JSMethod *JSDebugger::FindMethod(const PtLocation &location) const
|
||||
});
|
||||
return method;
|
||||
}
|
||||
|
||||
void JSDebugger::MethodEntry(ManagedThread *thread, Method *method)
|
||||
{
|
||||
if (hooks_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t threadId = thread->GetId();
|
||||
PtThread ptThread(threadId);
|
||||
hooks_->MethodEntry(ptThread, MethodToPtMethod(method));
|
||||
}
|
||||
|
||||
void JSDebugger::MethodExit(ManagedThread *thread, Method *method)
|
||||
{
|
||||
if (hooks_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
bool isExceptionTriggered = thread->HasPendingException();
|
||||
PtThread ptThread(thread->GetId());
|
||||
auto sp = const_cast<JSTaggedType *>(JSThread::Cast(thread)->GetCurrentSPFrame());
|
||||
InterpretedFrameHandler frameHandler(sp);
|
||||
PtValue retValue(frameHandler.GetAcc().GetRawData());
|
||||
hooks_->MethodExit(ptThread, MethodToPtMethod(method), isExceptionTriggered, retValue);
|
||||
}
|
||||
} // panda::tooling::ecmascript
|
@ -52,29 +52,35 @@ public:
|
||||
std::optional<Error> SetBreakpoint(const PtLocation &location) override;
|
||||
std::optional<Error> RemoveBreakpoint(const PtLocation &location) override;
|
||||
void BytecodePcChanged(ManagedThread *thread, Method *method, uint32_t bcOffset) override;
|
||||
void MethodEntry(ManagedThread *thread, Method *method) override;
|
||||
void MethodExit(ManagedThread *thread, Method *method) override;
|
||||
void LoadModule(std::string_view filename) override
|
||||
{
|
||||
if (hooks_ != nullptr) {
|
||||
hooks_->LoadModule(filename);
|
||||
if (hooks_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
hooks_->LoadModule(filename);
|
||||
}
|
||||
void VmStart() override
|
||||
{
|
||||
if (hooks_ != nullptr) {
|
||||
hooks_->VmStart();
|
||||
if (hooks_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
hooks_->VmStart();
|
||||
}
|
||||
void VmInitialization(ManagedThread::ThreadId threadId) override
|
||||
{
|
||||
if (hooks_ != nullptr) {
|
||||
hooks_->VmInitialization(PtThread(threadId));
|
||||
if (hooks_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
hooks_->VmInitialization(PtThread(threadId));
|
||||
}
|
||||
void VmDeath() override
|
||||
{
|
||||
if (hooks_ != nullptr) {
|
||||
hooks_->VmDeath();
|
||||
if (hooks_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
hooks_->VmDeath();
|
||||
}
|
||||
|
||||
PtLangExt *GetLangExtension() const override
|
||||
@ -115,8 +121,6 @@ public:
|
||||
void GarbageCollectorFinish() override {}
|
||||
void ObjectAlloc(BaseClass *klass, ObjectHeader *object, ManagedThread *thread, size_t size) override {}
|
||||
void ExceptionCatch(const ManagedThread *thread, const Method *method, uint32_t bcOffset) override {}
|
||||
void MethodEntry(ManagedThread *thread, Method *method) override {}
|
||||
void MethodExit(ManagedThread *thread, Method *method) override {}
|
||||
void ClassLoad(Class *klass) override {}
|
||||
void ClassPrepare(Class *klass) override {}
|
||||
void MonitorWait(ObjectHeader *object, int64_t timeout) override {}
|
||||
@ -221,7 +225,8 @@ public:
|
||||
private:
|
||||
static constexpr uint32_t JSDEBUG_EVENT_MASK = RuntimeNotificationManager::Event::LOAD_MODULE |
|
||||
RuntimeNotificationManager::Event::BYTECODE_PC_CHANGED |
|
||||
RuntimeNotificationManager::Event::VM_EVENTS;
|
||||
RuntimeNotificationManager::Event::VM_EVENTS |
|
||||
RuntimeNotificationManager::Event::METHOD_EVENTS;
|
||||
|
||||
JSMethod *FindMethod(const PtLocation &location) const;
|
||||
bool FindBreakpoint(const JSMethod *method, uint32_t bcOffset) const;
|
||||
|
80
ecmascript/tooling/js_pt_lang_ext.h
Normal file
80
ecmascript/tooling/js_pt_lang_ext.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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_TOOLING_JS_PT_LANG_EXT_H
|
||||
#define ECMASCRIPT_TOOLING_JS_PT_LANG_EXT_H
|
||||
|
||||
namespace panda::tooling::ecmascript {
|
||||
class JSPtLangExt : public PtLangExt {
|
||||
public:
|
||||
JSPtLangExt() = default;
|
||||
~JSPtLangExt() override = default;
|
||||
|
||||
// PtValue API
|
||||
PtObject ValueToObject(PtValue value) const override
|
||||
{
|
||||
return PtObject();
|
||||
}
|
||||
|
||||
// PtClass API
|
||||
PtClass GetClass(PtObject object) const override
|
||||
{
|
||||
return PtClass();
|
||||
}
|
||||
PtClass GetClass(PtProperty property) const override
|
||||
{
|
||||
return PtClass();
|
||||
}
|
||||
void ReleaseClass(PtClass klass) const override {}
|
||||
const char *GetClassDescriptor(PtClass klass) const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// PtObject API
|
||||
PandaList<PtProperty> GetProperties(PtObject object) const override
|
||||
{
|
||||
return {};
|
||||
}
|
||||
PtProperty GetProperty(PtObject object, const char *propertyName) const override
|
||||
{
|
||||
return PtProperty();
|
||||
}
|
||||
bool AddProperty(PtObject object, const char *propertyName, PtValue value) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bool RemoveProperty(PtObject object, const char *propertyName) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// PtProperty API
|
||||
const char *GetPropertyName(PtProperty property) const override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
PtValue GetPropertyValue(PtProperty property) const override
|
||||
{
|
||||
return PtValue();
|
||||
}
|
||||
void SetPropertyPtValue(PtProperty property, PtValue value) const override {}
|
||||
void ReleasePtValue(const PtValue *value) const override {}
|
||||
|
||||
NO_COPY_SEMANTIC(JSPtLangExt);
|
||||
NO_MOVE_SEMANTIC(JSPtLangExt);
|
||||
};
|
||||
} // panda::tooling::ecmascript
|
||||
#endif // ECMASCRIPT_TOOLING_JS_PT_LANG_EXT_H
|
@ -84,11 +84,11 @@ void ProtocolHandler::SendResponse(const DispatchRequest &request, const Dispatc
|
||||
|
||||
void ProtocolHandler::SendNotification(const EcmaVM *ecmaVm, std::unique_ptr<PtBaseEvents> events)
|
||||
{
|
||||
if (!Runtime::GetCurrent()->IsDebugMode() || events == nullptr) {
|
||||
return;
|
||||
}
|
||||
LOG(DEBUG, DEBUGGER) << "ProtocolHandler::SendNotification: " << events->GetName();
|
||||
SendReply(ecmaVm, events->ToObject(ecmaVm));
|
||||
if (!Runtime::GetCurrent()->IsDebugMode() || events == nullptr) {
|
||||
return;
|
||||
}
|
||||
LOG(DEBUG, DEBUGGER) << "ProtocolHandler::SendNotification: " << events->GetName();
|
||||
SendReply(ecmaVm, events->ToObject(ecmaVm));
|
||||
}
|
||||
|
||||
void ProtocolHandler::SendReply(const EcmaVM *ecmaVm, Local<ObjectRef> reply)
|
||||
|
@ -43,12 +43,38 @@ ts2abc_gen_abc("ark_debug_abc") {
|
||||
out_puts = [ test_abc_path ]
|
||||
}
|
||||
|
||||
ohos_shared_library("debugger_entry") {
|
||||
sources = [ "entry/test_debugger_entry.cpp" ]
|
||||
|
||||
configs = [
|
||||
"//ark/js_runtime:ark_jsruntime_public_config", # should add before
|
||||
# arkruntime_public_config
|
||||
"//ark/js_runtime:ark_jsruntime_common_config",
|
||||
":debug_api_test",
|
||||
"$ark_root/runtime:arkruntime_public_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":ark_debug_abc",
|
||||
":jsdebugtest",
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"$ark_root/libpandafile:libarkfile",
|
||||
]
|
||||
|
||||
if (!is_standard_system) {
|
||||
deps += [ "$ark_root/runtime:libarkruntime" ]
|
||||
}
|
||||
|
||||
output_extension = "so"
|
||||
subsystem_name = "test"
|
||||
}
|
||||
|
||||
ohos_shared_library("jsdebugtest") {
|
||||
sources = [
|
||||
"init.cpp",
|
||||
"test_extractor.cpp",
|
||||
"test_list.cpp",
|
||||
"test_util.cpp",
|
||||
"utils/test_entry.cpp",
|
||||
"utils/test_extractor.cpp",
|
||||
"utils/test_util.cpp",
|
||||
"utils/testcases/test_list.cpp",
|
||||
]
|
||||
|
||||
configs = [
|
||||
@ -81,9 +107,11 @@ ohos_unittest("EcmaDebugApiTest") {
|
||||
|
||||
sources = [
|
||||
# test file
|
||||
"launcher.cpp",
|
||||
"debugger_api_test.cpp",
|
||||
]
|
||||
|
||||
defines = [ "DEBUGGER_TEST_LIBRARY=\"libdebugger_entry.so\"" ]
|
||||
|
||||
configs = [
|
||||
"//ark/js_runtime:ark_jsruntime_public_config", # should add before
|
||||
# arkruntime_public_config
|
||||
@ -93,7 +121,6 @@ ohos_unittest("EcmaDebugApiTest") {
|
||||
]
|
||||
|
||||
deps = [
|
||||
":ark_debug_abc",
|
||||
":jsdebugtest",
|
||||
"$ark_root/libpandabase:libarkbase",
|
||||
"$ark_root/libpandafile:libarkfile",
|
||||
@ -194,6 +221,7 @@ group("unittest") {
|
||||
":DebuggerEventsTest",
|
||||
":DebuggerTypesTest",
|
||||
":EcmaDebugApiTest",
|
||||
":debugger_entry",
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1,102 +0,0 @@
|
||||
/*
|
||||
* 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_TOOLING_TEST_JS_SINGLE_STEP_TEST_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_JS_SINGLE_STEP_TEST_H
|
||||
|
||||
#include "ecmascript/tooling/test/test_util.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
class JsSingleStepTest : public ApiTest {
|
||||
public:
|
||||
JsSingleStepTest()
|
||||
{
|
||||
vm_start = [this] {
|
||||
location_start_ = TestUtil::GetLocation("Sample.js", 4, panda_file_.c_str());
|
||||
location_end_ = TestUtil::GetLocation("Sample.js", 7, panda_file_.c_str());
|
||||
return true;
|
||||
};
|
||||
|
||||
vm_death = [this]() {
|
||||
ASSERT_NE(step_count_, 0);
|
||||
ASSERT_EQ(breakpoint_count_, 2);
|
||||
return true;
|
||||
};
|
||||
|
||||
load_module = [this](std::string_view moduleName) {
|
||||
if (flag) {
|
||||
if (moduleName.find(panda_file_.c_str()) == std::string_view::npos) {
|
||||
return true;
|
||||
}
|
||||
flag = 0;
|
||||
ASSERT_SUCCESS(debug_interface->SetBreakpoint(location_end_));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
breakpoint = [this](PtThread, const PtLocation &location) {
|
||||
ASSERT_TRUE(location.GetMethodId().IsValid());
|
||||
ASSERT_LOCATION_EQ(location, location_end_);
|
||||
// Check what step signalled before breakpoint
|
||||
ASSERT_LOCATION_EQ(location, location_step_);
|
||||
ASSERT_TRUE(collect_steps_);
|
||||
breakpoint_count_++;
|
||||
// Disable collect steps
|
||||
collect_steps_ = false;
|
||||
return true;
|
||||
};
|
||||
|
||||
single_step = [this](PtThread, const PtLocation &location) {
|
||||
ASSERT_TRUE(location.GetMethodId().IsValid());
|
||||
if (!collect_steps_) {
|
||||
if (location_start_ == location) {
|
||||
collect_steps_ = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ASSERT_NE(bytecode_offset_, location.GetBytecodeOffset());
|
||||
location_step_ = location;
|
||||
step_count_++;
|
||||
bytecode_offset_ = location.GetBytecodeOffset();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
std::pair<CString, CString> GetEntryPoint() override
|
||||
{
|
||||
return {panda_file_, entry_point_};
|
||||
}
|
||||
|
||||
private:
|
||||
CString panda_file_ = "/data/app/Sample.abc";
|
||||
CString entry_point_ = "_GLOBAL::func_main_0";
|
||||
PtLocation location_start_{nullptr, PtLocation::EntityId(0), 0};
|
||||
PtLocation location_end_{nullptr, PtLocation::EntityId(0), 0};
|
||||
PtLocation location_step_{nullptr, PtLocation::EntityId(0), 0};
|
||||
int32_t step_count_ = 0;
|
||||
int32_t breakpoint_count_ = 0;
|
||||
bool collect_steps_ = false;
|
||||
uint32_t bytecode_offset_ = std::numeric_limits<uint32_t>::max();
|
||||
bool flag = 1;
|
||||
};
|
||||
|
||||
std::unique_ptr<ApiTest> GetJsSingleStepTest()
|
||||
{
|
||||
return std::make_unique<JsSingleStepTest>();
|
||||
}
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_JS_SINGLE_STEP_TEST_H
|
@ -16,7 +16,7 @@
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/napi/include/jsnapi.h"
|
||||
#include "ecmascript/tests/test_helper.h"
|
||||
#include "ecmascript/tooling/test/test_list.h"
|
||||
#include "ecmascript/tooling/test/utils/testcases/test_list.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
using panda::ecmascript::EcmaHandleScope;
|
||||
@ -24,7 +24,7 @@ using panda::ecmascript::EcmaVM;
|
||||
using panda::ecmascript::JSThread;
|
||||
using panda::test::TestHelper;
|
||||
|
||||
class EcmaScriptDebugApiTest : public testing::TestWithParam<const char *> {
|
||||
class DebuggerApiTest : public testing::TestWithParam<const char *> {
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
@ -38,7 +38,8 @@ public:
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
|
||||
SetCurrentTestName(GetParam());
|
||||
TestHelper::CreateEcmaVMWithScope(instance, thread, scope, DEBUGGER_TEST_LIBRARY);
|
||||
}
|
||||
|
||||
void TearDown() override
|
||||
@ -49,30 +50,22 @@ public:
|
||||
PandaVM *instance {nullptr};
|
||||
EcmaHandleScope *scope {nullptr};
|
||||
JSThread *thread {nullptr};
|
||||
|
||||
protected:
|
||||
void RunEcmaScriptTest(const char *testName)
|
||||
{
|
||||
std::cout << "Running " << testName << std::endl;
|
||||
SetCurrentTestName(testName);
|
||||
EcmaVM *vm = EcmaVM::Cast(instance);
|
||||
ASSERT_NE(vm, nullptr);
|
||||
auto [pandaFile, entryPoint] = GetTestEntryPoint(testName);
|
||||
|
||||
auto fileNameRef = StringRef::NewFromUtf8(vm, pandaFile.c_str(), pandaFile.size());
|
||||
auto entryRef = StringRef::NewFromUtf8(vm, entryPoint.c_str(), entryPoint.size());
|
||||
auto res = JSNApi::Execute(vm, fileNameRef, entryRef);
|
||||
ASSERT_TRUE(res);
|
||||
}
|
||||
};
|
||||
|
||||
HWTEST_P_L0(EcmaScriptDebugApiTest, EcmaScriptSuite)
|
||||
HWTEST_P_L0(DebuggerApiTest, EcmaScriptSuite)
|
||||
{
|
||||
const char *testName = GetParam();
|
||||
ASSERT_NE(testName, nullptr);
|
||||
RunEcmaScriptTest(testName);
|
||||
const char *testName = GetCurrentTestName();
|
||||
std::cout << "Running " << testName << std::endl;
|
||||
EcmaVM *vm = EcmaVM::Cast(instance);
|
||||
ASSERT_NE(vm, nullptr);
|
||||
auto [pandaFile, entryPoint] = GetTestEntryPoint(testName);
|
||||
|
||||
auto fileNameRef = StringRef::NewFromUtf8(vm, pandaFile.c_str(), pandaFile.size());
|
||||
auto entryRef = StringRef::NewFromUtf8(vm, entryPoint.c_str(), entryPoint.size());
|
||||
auto res = JSNApi::Execute(vm, fileNameRef, entryRef);
|
||||
ASSERT_TRUE(res);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(EcmaDebugApiTest, EcmaScriptDebugApiTest,
|
||||
INSTANTIATE_TEST_CASE_P(EcmaDebugApiTest, DebuggerApiTest,
|
||||
testing::ValuesIn(GetTestList(panda::panda_file::SourceLang::ECMASCRIPT)));
|
||||
} // namespace panda::tooling::ecmascript::test
|
@ -13,11 +13,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Js
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_JS_VM_EVENT_TEST_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_JS_VM_EVENT_TEST_H
|
||||
#include "ecmascript/tooling/test/utils/test_entry.h"
|
||||
|
||||
#include "js/js_breakpoint_test.h"
|
||||
#include "js/js_single_step_test.h"
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
extern "C" int StartDebugger()
|
||||
{
|
||||
return StartDebuggerImpl();
|
||||
}
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_JS_VM_EVENT_TEST_H
|
||||
extern "C" int StopDebugger()
|
||||
{
|
||||
return StopDebuggerImpl();
|
||||
}
|
||||
} // namespace panda::tooling::ecmascript::test
|
@ -13,35 +13,34 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include "ecmascript/tooling/test/utils/test_entry.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "ecmascript/tooling/test/test_runner.h"
|
||||
#include "ecmascript/tooling/test/test_util.h"
|
||||
#include "ecmascript/tooling/test/utils/testcases/test_list.h"
|
||||
#include "ecmascript/tooling/test/utils/test_hooks.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
extern const char *GetCurrentTestName();
|
||||
|
||||
static std::thread g_debuggerThread;
|
||||
static std::unique_ptr<TestHooks> g_hooks = nullptr;
|
||||
|
||||
static std::unique_ptr<TestRunner> g_runner{nullptr};
|
||||
|
||||
extern "C" int32_t StartDebugger(const EcmaVM *vm)
|
||||
int StartDebuggerImpl()
|
||||
{
|
||||
const char *testName = GetCurrentTestName();
|
||||
g_runner = std::make_unique<TestRunner>(testName, vm);
|
||||
EcmaVM *vm = EcmaVM::Cast(Runtime::GetCurrent()->GetPandaVM());
|
||||
g_hooks = std::make_unique<TestHooks>(testName, vm);
|
||||
g_debuggerThread = std::thread([] {
|
||||
TestUtil::WaitForInit();
|
||||
g_runner->Run();
|
||||
g_hooks->Run();
|
||||
});
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int32_t StopDebugger()
|
||||
int StopDebuggerImpl()
|
||||
{
|
||||
g_debuggerThread.join();
|
||||
g_runner->TerminateTest();
|
||||
g_runner.reset();
|
||||
g_hooks->TerminateTest();
|
||||
g_hooks.reset();
|
||||
return 0;
|
||||
}
|
||||
} // namespace panda::tooling::ecmascript::test
|
24
ecmascript/tooling/test/utils/test_entry.h
Normal file
24
ecmascript/tooling/test/utils/test_entry.h
Normal file
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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_TOOLING_TEST_UTILS_TEST_ENTRY_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_ENTRY_H
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
int StartDebuggerImpl();
|
||||
int StopDebuggerImpl();
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TEST_ENTRY_H
|
@ -13,8 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_API_TEST_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_API_TEST_H
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TEST_EVENTS_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_EVENTS_H
|
||||
|
||||
#include <utility>
|
||||
#include "ecmascript/tooling/agent/js_backend.h"
|
||||
@ -47,25 +47,25 @@ enum class DebugEvent {
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, DebugEvent value);
|
||||
|
||||
struct ApiTest {
|
||||
struct TestEvents {
|
||||
BreakpointCallback breakpoint;
|
||||
LoadModuleCallback load_module;
|
||||
LoadModuleCallback loadModule;
|
||||
PausedCallback paused;
|
||||
ExceptionCallback exception;
|
||||
MethodEntryCallback method_entry;
|
||||
SingleStepCallback single_step;
|
||||
VmStartCallback vm_start;
|
||||
VmInitializationCallback vm_init;
|
||||
VmDeathCallback vm_death;
|
||||
MethodEntryCallback methodEntry;
|
||||
SingleStepCallback singleStep;
|
||||
VmStartCallback vmStart;
|
||||
VmInitializationCallback vmInit;
|
||||
VmDeathCallback vmDeath;
|
||||
|
||||
Scenario scenario;
|
||||
JSDebugger *debug_interface {nullptr};
|
||||
JSBackend *backend {nullptr};
|
||||
ApiTest();
|
||||
virtual ~ApiTest() = default;
|
||||
JSDebugger *debugInterface_ {nullptr};
|
||||
JSBackend *backend_ {nullptr};
|
||||
TestEvents();
|
||||
virtual ~TestEvents() = default;
|
||||
|
||||
virtual std::pair<CString, CString> GetEntryPoint() = 0;
|
||||
};
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_API_TEST_H
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TEST_EVENTS_H
|
@ -14,10 +14,7 @@
|
||||
*/
|
||||
// Taken from panda-tools/panda-debugger/debugger
|
||||
|
||||
#include "ecmascript/tooling/test/test_extractor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include "ecmascript/tooling/test/utils/test_extractor.h"
|
||||
|
||||
#include "libpandabase/utils/leb128.h"
|
||||
#include "libpandabase/utils/utf.h"
|
@ -13,8 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_DEBUG_INFO_EXTRACTOR_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_DEBUG_INFO_EXTRACTOR_H
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TEST_EXTRACTOR_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_EXTRACTOR_H
|
||||
|
||||
#include "ecmascript/mem/c_string.h"
|
||||
#include "ecmascript/tooling/pt_js_extractor.h"
|
||||
@ -58,4 +58,4 @@ public:
|
||||
};
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_DEBUG_INFO_EXTRACTOR_H
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TEST_EXTRACTOR_H
|
@ -13,26 +13,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_TEST_RUNNER_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_TEST_RUNNER_H
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TEST_HOOKS_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_HOOKS_H
|
||||
|
||||
#include "ecmascript/tooling/test/test_util.h"
|
||||
#include "ecmascript/tooling/agent/js_pt_hooks.h"
|
||||
#include "ecmascript/tooling/agent/js_backend.h"
|
||||
#include "ecmascript/tooling/test/utils/test_util.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
class TestRunner : public PtHooks {
|
||||
class TestHooks : public PtHooks {
|
||||
public:
|
||||
TestRunner(const char *test_name, const EcmaVM *vm)
|
||||
TestHooks(const char *testName, const EcmaVM *vm)
|
||||
{
|
||||
backend_ = std::make_unique<JSBackend>(vm);
|
||||
test_name_ = test_name;
|
||||
test_ = TestUtil::GetTest(test_name);
|
||||
test_->backend = backend_.get();
|
||||
test_->debug_interface = backend_->GetDebugger();
|
||||
debug_interface_ = backend_->GetDebugger();
|
||||
testName_ = testName;
|
||||
test_ = TestUtil::GetTest(testName);
|
||||
test_->backend_ = backend_.get();
|
||||
test_->debugInterface_ = backend_->GetDebugger();
|
||||
debugInterface_ = backend_->GetDebugger();
|
||||
TestUtil::Reset();
|
||||
debug_interface_->RegisterHooks(this);
|
||||
debugInterface_->RegisterHooks(this);
|
||||
}
|
||||
|
||||
void Run()
|
||||
@ -51,8 +51,8 @@ public:
|
||||
|
||||
void LoadModule(std::string_view panda_file_name) override
|
||||
{
|
||||
if (test_->load_module) {
|
||||
test_->load_module(panda_file_name);
|
||||
if (test_->loadModule) {
|
||||
test_->loadModule(panda_file_name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,48 +73,48 @@ public:
|
||||
|
||||
void MethodEntry(PtThread thread, PtMethod method) override
|
||||
{
|
||||
if (test_->method_entry) {
|
||||
test_->method_entry(thread, method);
|
||||
if (test_->methodEntry) {
|
||||
test_->methodEntry(thread, method);
|
||||
}
|
||||
}
|
||||
|
||||
void SingleStep(PtThread thread, const PtLocation &location) override
|
||||
{
|
||||
if (test_->single_step) {
|
||||
test_->single_step(thread, location);
|
||||
if (test_->singleStep) {
|
||||
test_->singleStep(thread, location);
|
||||
}
|
||||
}
|
||||
|
||||
void VmDeath() override
|
||||
{
|
||||
if (test_->vm_death) {
|
||||
test_->vm_death();
|
||||
if (test_->vmDeath) {
|
||||
test_->vmDeath();
|
||||
}
|
||||
TestUtil::Event(DebugEvent::VM_DEATH);
|
||||
}
|
||||
|
||||
void VmInitialization([[maybe_unused]] PtThread thread) override
|
||||
{
|
||||
if (test_->vm_init) {
|
||||
test_->vm_init();
|
||||
if (test_->vmInit) {
|
||||
test_->vmInit();
|
||||
}
|
||||
TestUtil::Event(DebugEvent::VM_INITIALIZATION);
|
||||
}
|
||||
|
||||
void VmStart() override
|
||||
{
|
||||
if (test_->vm_start) {
|
||||
test_->vm_start();
|
||||
if (test_->vmStart) {
|
||||
test_->vmStart();
|
||||
}
|
||||
}
|
||||
|
||||
void TerminateTest()
|
||||
{
|
||||
debug_interface_->RegisterHooks(nullptr);
|
||||
debugInterface_->RegisterHooks(nullptr);
|
||||
if (TestUtil::IsTestFinished()) {
|
||||
return;
|
||||
}
|
||||
LOG(FATAL, DEBUGGER) << "Test " << test_name_ << " failed";
|
||||
LOG(FATAL, DEBUGGER) << "Test " << testName_ << " failed";
|
||||
}
|
||||
|
||||
void ThreadStart(PtThread) override {}
|
||||
@ -139,14 +139,14 @@ public:
|
||||
void ExecutionContextsCleared() override {}
|
||||
void InspectRequested(PtObject, PtObject) override {}
|
||||
|
||||
~TestRunner() = default;
|
||||
~TestHooks() = default;
|
||||
|
||||
private:
|
||||
std::unique_ptr<JSBackend> backend_ {nullptr};
|
||||
JSDebugger *debug_interface_;
|
||||
const char *test_name_;
|
||||
ApiTest *test_;
|
||||
JSDebugger *debugInterface_;
|
||||
const char *testName_;
|
||||
TestEvents *test_;
|
||||
};
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_TEST_RUNNER_H
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TEST_HOOKS_H
|
@ -13,7 +13,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecmascript/tooling/test/test_util.h"
|
||||
#include "ecmascript/tooling/test/utils/test_util.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
TestMap TestUtil::testMap_;
|
||||
@ -56,7 +56,7 @@ int32_t TestUtil::GetValueRegister(JSMethod *method, const char *varName)
|
||||
}
|
||||
}
|
||||
|
||||
return -2;
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, DebugEvent value)
|
||||
@ -66,7 +66,7 @@ std::ostream &operator<<(std::ostream &out, DebugEvent value)
|
||||
#define ADD_CASE(entry) \
|
||||
case (entry): \
|
||||
s = #entry; \
|
||||
break;
|
||||
break
|
||||
|
||||
switch (value) {
|
||||
ADD_CASE(DebugEvent::BREAKPOINT);
|
||||
@ -93,7 +93,7 @@ std::ostream &operator<<(std::ostream &out, std::nullptr_t)
|
||||
return out << "nullptr";
|
||||
}
|
||||
|
||||
ApiTest::ApiTest()
|
||||
TestEvents::TestEvents()
|
||||
{
|
||||
scenario = []() {
|
||||
ASSERT_EXITED();
|
@ -13,37 +13,34 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_TEST_UTIL_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_TEST_UTIL_H
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TEST_UTIL_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_UTIL_H
|
||||
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "api_test.h"
|
||||
#include "ecmascript/mem/c_containers.h"
|
||||
#include "ecmascript/tooling/interface/js_debugger.h"
|
||||
#include "ecmascript/tooling/test/utils/test_events.h"
|
||||
#include "ecmascript/tooling/test/utils/test_extractor.h"
|
||||
#include "os/mutex.h"
|
||||
#include "test_extractor.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
using TestMap = std::unordered_map<panda_file::SourceLang, std::unordered_map<const char *, std::unique_ptr<ApiTest>>>;
|
||||
template<class Key, class T, class Hash = std::hash<Key>, class KeyEqual = std::equal_to<Key>>
|
||||
using CUnorderedMap = panda::ecmascript::CUnorderedMap<Key, T, Hash, KeyEqual>;
|
||||
using TestMap = CUnorderedMap<panda_file::SourceLang, CUnorderedMap<const char *, std::unique_ptr<TestEvents>>>;
|
||||
|
||||
class TestUtil {
|
||||
public:
|
||||
static void RegisterTest(panda_file::SourceLang language, const char *testName, std::unique_ptr<ApiTest> test)
|
||||
static void RegisterTest(panda_file::SourceLang language, const char *testName, std::unique_ptr<TestEvents> test)
|
||||
{
|
||||
auto it = testMap_.find(language);
|
||||
if (it == testMap_.end()) {
|
||||
std::unordered_map<const char *, std::unique_ptr<ApiTest>> entry;
|
||||
CUnorderedMap<const char *, std::unique_ptr<TestEvents>> entry;
|
||||
auto res = testMap_.emplace(language, std::move(entry));
|
||||
it = res.first;
|
||||
}
|
||||
it->second.insert({testName, std::move(test)});
|
||||
}
|
||||
|
||||
static ApiTest *GetTest(const char *name)
|
||||
static TestEvents *GetTest(const char *name)
|
||||
{
|
||||
for (auto it = testMap_.begin(); it != testMap_.end(); ++it) {
|
||||
auto &internalMap = it->second;
|
||||
@ -75,13 +72,17 @@ public:
|
||||
static bool WaitForExit()
|
||||
{
|
||||
return WaitForEvent(DebugEvent::VM_DEATH,
|
||||
[]() REQUIRES(eventMutex_) { return lastEvent_ == DebugEvent::VM_DEATH; }, [] {});
|
||||
[]() REQUIRES(eventMutex_) {
|
||||
return lastEvent_ == DebugEvent::VM_DEATH;
|
||||
}, [] {});
|
||||
}
|
||||
|
||||
static bool WaitForInit()
|
||||
{
|
||||
return WaitForEvent(DebugEvent::VM_INITIALIZATION,
|
||||
[]() REQUIRES(eventMutex_) { return initialized_; }, [] {});
|
||||
[]() REQUIRES(eventMutex_) {
|
||||
return initialized_;
|
||||
}, [] {});
|
||||
}
|
||||
|
||||
static void Event(DebugEvent event, PtThread thread = PtThread::NONE,
|
||||
@ -126,14 +127,7 @@ public:
|
||||
|
||||
TestExtractor extractor(pf);
|
||||
auto [id, offset] = extractor.GetBreakpointAddress({sourceFile, line});
|
||||
#if PANDA_LIBCORE_SUPPORT
|
||||
static std::unordered_set<std::string> absolute_paths;
|
||||
static char buf[PATH_MAX];
|
||||
auto res = absolute_paths.insert(::realpath(pandaFile, buf));
|
||||
return PtLocation(res.first->c_str(), id, offset);
|
||||
#else // PANDA_LIBCORE_SUPPORT
|
||||
return PtLocation(pandaFile, id, offset);
|
||||
#endif // PANDA_LIBCORE_SUPPORT
|
||||
}
|
||||
|
||||
static std::vector<panda_file::LocalVariableInfo> GetVariables(JSMethod *method, uint32_t offset);
|
||||
@ -205,88 +199,91 @@ private:
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, std::nullptr_t);
|
||||
|
||||
#define _ASSERT_FAIL(val1, val2, strval1, strval2, msg) \
|
||||
std::cerr << "Assertion failed at " << __FILE__ << ':' << __LINE__ << std::endl; \
|
||||
std::cerr << "Expected that " strval1 " is " << msg << " " strval2 << std::endl; \
|
||||
std::cerr << "\t" strval1 ": " << (val1) << std::endl; \
|
||||
std::cerr << "\t" strval2 ": " << (val2) << std::endl; \
|
||||
std::abort();
|
||||
|
||||
#define ASSERT_TRUE(cond) \
|
||||
do { \
|
||||
auto res = (cond); \
|
||||
if (!res) { \
|
||||
_ASSERT_FAIL(res, true, #cond, "true", "equal to") \
|
||||
} \
|
||||
#define ASSERT_FAIL_(val1, val2, strval1, strval2, msg) \
|
||||
do { \
|
||||
std::cerr << "Assertion failed at " << __FILE__ << ':' << __LINE__ << std::endl; \
|
||||
std::cerr << "Expected that " strval1 " is " << (msg) << " " strval2 << std::endl; \
|
||||
std::cerr << "\t" strval1 ": " << (val1) << std::endl; \
|
||||
std::cerr << "\t" strval2 ": " << (val2) << std::endl; \
|
||||
std::abort(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_FALSE(cond) \
|
||||
do { \
|
||||
auto res = (cond); \
|
||||
if (res) { \
|
||||
_ASSERT_FAIL(res, false, #cond, "false", "equal to") \
|
||||
} \
|
||||
#define ASSERT_TRUE(cond) \
|
||||
do { \
|
||||
auto res = (cond); \
|
||||
if (!res) { \
|
||||
ASSERT_FAIL_(res, true, #cond, "true", "equal to"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_EQ(lhs, rhs) \
|
||||
#define ASSERT_FALSE(cond) \
|
||||
do { \
|
||||
auto res = (cond); \
|
||||
if (res) { \
|
||||
ASSERT_FAIL_(res, false, #cond, "false", "equal to"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_EQ(lhs, rhs) \
|
||||
do { \
|
||||
auto res1 = (lhs); \
|
||||
decltype(res1) res2 = (rhs); \
|
||||
if (res1 != res2) { \
|
||||
ASSERT_FAIL_(res1, res2, #lhs, #rhs, "equal to"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_NE(lhs, rhs) \
|
||||
do { \
|
||||
auto res1 = (lhs); \
|
||||
decltype(res1) res2 = (rhs); \
|
||||
if (res1 == res2) { \
|
||||
ASSERT_FAIL_(res1, res2, #lhs, #rhs, "not equal to"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_STREQ(lhs, rhs) \
|
||||
do { \
|
||||
auto res1 = (lhs); \
|
||||
decltype(res1) res2 = (rhs); \
|
||||
if (::strcmp(res1, res2) != 0) { \
|
||||
ASSERT_FAIL_(res1, res2, #lhs, #rhs, "equal to"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_SUCCESS(api_call) \
|
||||
do { \
|
||||
auto error = api_call; \
|
||||
if (error) { \
|
||||
ASSERT_FAIL_(error.value().GetMessage(), "Success", "API call result", "Expected", ""); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_EXITED() \
|
||||
do { \
|
||||
bool res = TestUtil::WaitForExit(); \
|
||||
if (!res) { \
|
||||
ASSERT_FAIL_(TestUtil::IsTestFinished(), true, "TestUtil::IsTestFinished()", "true", ""); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_LOCATION_EQ(lhs, rhs) \
|
||||
do { \
|
||||
ASSERT_STREQ((lhs).GetPandaFile(), (rhs).GetPandaFile()); \
|
||||
ASSERT_EQ((lhs).GetMethodId().GetOffset(), (rhs).GetMethodId().GetOffset()); \
|
||||
ASSERT_EQ((lhs).GetBytecodeOffset(), (rhs).GetBytecodeOffset()); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_THREAD_VALID(ecmaVm) \
|
||||
do { \
|
||||
auto res1 = (lhs); \
|
||||
decltype(res1) res2 = (rhs); \
|
||||
if (res1 != res2) { \
|
||||
_ASSERT_FAIL(res1, res2, #lhs, #rhs, "equal to") \
|
||||
} \
|
||||
ASSERT_NE((ecmaVm).GetId(), PtThread::NONE.GetId()); \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_NE(lhs, rhs) \
|
||||
do { \
|
||||
auto res1 = (lhs); \
|
||||
decltype(res1) res2 = (rhs); \
|
||||
if (res1 == res2) { \
|
||||
_ASSERT_FAIL(res1, res2, #lhs, #rhs, "not equal to") \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_STREQ(lhs, rhs) \
|
||||
do { \
|
||||
auto res1 = (lhs); \
|
||||
decltype(res1) res2 = (rhs); \
|
||||
if (::strcmp(res1, res2) != 0) { \
|
||||
_ASSERT_FAIL(res1, res2, #lhs, #rhs, "equal to") \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_SUCCESS(api_call) \
|
||||
do { \
|
||||
auto error = api_call; \
|
||||
if (error) { \
|
||||
_ASSERT_FAIL(error.value().GetMessage(), "Success", "API call result", "Expected", "") \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_EXITED() \
|
||||
do { \
|
||||
bool res = TestUtil::WaitForExit(); \
|
||||
if (!res) { \
|
||||
_ASSERT_FAIL(TestUtil::IsTestFinished(), true, "TestUtil::IsTestFinished()", "true", "") \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSERT_LOCATION_EQ(lhs, rhs) \
|
||||
do { \
|
||||
ASSERT_STREQ(lhs.GetPandaFile(), rhs.GetPandaFile()); \
|
||||
ASSERT_EQ(lhs.GetMethodId().GetOffset(), rhs.GetMethodId().GetOffset()); \
|
||||
ASSERT_EQ(lhs.GetBytecodeOffset(), rhs.GetBytecodeOffset()); \
|
||||
} while (0);
|
||||
|
||||
#define ASSERT_THREAD_VALID(ecmaVm) \
|
||||
do { \
|
||||
ASSERT_NE(ecmaVm.GetId(), PtThread::NONE.GetId()); \
|
||||
} while (0);
|
||||
|
||||
#define ASSERT_BREAKPOINT_SUCCESS(location) \
|
||||
do { \
|
||||
PtThread suspended = TestUtil::WaitForBreakpoint(location); \
|
||||
ASSERT_THREAD_VALID(suspended); \
|
||||
} while (0);
|
||||
} while (0)
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_TEST_UTIL_H
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TEST_UTIL_H
|
@ -13,20 +13,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_JS_BREAKPOINT_TEST_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_JS_BREAKPOINT_TEST_H
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_TEST_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_TEST_H
|
||||
|
||||
#include "ecmascript/tooling/test/test_util.h"
|
||||
#include "ecmascript/mem/c_string.h"
|
||||
#include "ecmascript/tooling/test/utils/test_util.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
class JsBreakpointTest : public ApiTest {
|
||||
class JsBreakpointTest : public TestEvents {
|
||||
public:
|
||||
JsBreakpointTest()
|
||||
{
|
||||
vm_start = [this] {
|
||||
location_ = TestUtil::GetLocation("Sample.js", 7, panda_file_.c_str());
|
||||
location_.GetPandaFile();
|
||||
vmStart = [this] {
|
||||
location_ = TestUtil::GetLocation("Sample.js", 22, pandaFile_.c_str());
|
||||
ASSERT_TRUE(location_.GetMethodId().IsValid());
|
||||
return true;
|
||||
};
|
||||
@ -34,57 +33,57 @@ public:
|
||||
breakpoint = [this](PtThread thread, const PtLocation &location) {
|
||||
ASSERT_TRUE(location.GetMethodId().IsValid());
|
||||
ASSERT_LOCATION_EQ(location, location_);
|
||||
++breakpoint_counter_;
|
||||
++breakpointCounter_;
|
||||
TestUtil::SuspendUntilContinue(DebugEvent::BREAKPOINT, thread, location);
|
||||
return true;
|
||||
};
|
||||
|
||||
load_module = [this](std::string_view moduleName) {
|
||||
loadModule = [this](std::string_view moduleName) {
|
||||
if (flag_) {
|
||||
if (moduleName.find(panda_file_.c_str()) == std::string_view::npos) {
|
||||
if (moduleName != pandaFile_) {
|
||||
return true;
|
||||
}
|
||||
ASSERT_TRUE(backend->NotifyScriptParsed(0, panda_file_));
|
||||
flag_ = 0;
|
||||
location_.GetPandaFile();
|
||||
ASSERT_SUCCESS(debug_interface->SetBreakpoint(location_));
|
||||
auto error = debug_interface->SetBreakpoint(location_);
|
||||
ASSERT_FALSE(!error);
|
||||
ASSERT_TRUE(backend_->NotifyScriptParsed(0, pandaFile_));
|
||||
flag_ = false;
|
||||
auto error = debugInterface_->SetBreakpoint(location_);
|
||||
ASSERT_FALSE(error.has_value());
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
scenario = [this]() {
|
||||
ASSERT_BREAKPOINT_SUCCESS(location_);
|
||||
ASSERT_SUCCESS(debug_interface->RemoveBreakpoint(location_));
|
||||
TestUtil::Continue();
|
||||
ASSERT_BREAKPOINT_SUCCESS(location_);
|
||||
TestUtil::Continue();
|
||||
ASSERT_SUCCESS(debugInterface_->RemoveBreakpoint(location_));
|
||||
ASSERT_EXITED();
|
||||
return true;
|
||||
};
|
||||
|
||||
vm_death = [this]() {
|
||||
ASSERT_EQ(breakpoint_counter_, 1U);
|
||||
vmDeath = [this]() {
|
||||
ASSERT_EQ(breakpointCounter_, 2U);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
std::pair<CString, CString> GetEntryPoint() override
|
||||
{
|
||||
return {panda_file_, entry_point_};
|
||||
return {pandaFile_, entryPoint_};
|
||||
}
|
||||
~JsBreakpointTest() = default;
|
||||
private:
|
||||
CString panda_file_ = "/data/app/Sample.abc";
|
||||
CString entry_point_ = "_GLOBAL::func_main_0";
|
||||
CString pandaFile_ = "/data/test/Sample.abc";
|
||||
CString entryPoint_ = "_GLOBAL::func_main_0";
|
||||
PtLocation location_ {nullptr, PtLocation::EntityId(0), 0};
|
||||
size_t breakpoint_counter_ = 0;
|
||||
bool flag_ = 1;
|
||||
size_t breakpointCounter_ = 0;
|
||||
bool flag_ = true;
|
||||
};
|
||||
|
||||
std::unique_ptr<ApiTest> GetJsBreakpointTest()
|
||||
std::unique_ptr<TestEvents> GetJsBreakpointTest()
|
||||
{
|
||||
return std::make_unique<JsBreakpointTest>();
|
||||
}
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_JS_BREAKPOINT_TEST_H
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_TEST_H
|
102
ecmascript/tooling/test/utils/testcases/js_single_step_test.h
Normal file
102
ecmascript/tooling/test/utils/testcases/js_single_step_test.h
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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_TOOLING_TEST_UTILS_TESTCASES_JS_SINGLE_STEP_TEST_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_SINGLE_STEP_TEST_H
|
||||
|
||||
#include "ecmascript/tooling/test/utils/test_util.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
class JsSingleStepTest : public TestEvents {
|
||||
public:
|
||||
JsSingleStepTest()
|
||||
{
|
||||
vmStart = [this] {
|
||||
locationStart_ = TestUtil::GetLocation("Sample.js", 19, pandaFile_.c_str());
|
||||
locationEnd_ = TestUtil::GetLocation("Sample.js", 22, pandaFile_.c_str());
|
||||
return true;
|
||||
};
|
||||
|
||||
vmDeath = [this]() {
|
||||
ASSERT_NE(stepCounter_, 0);
|
||||
ASSERT_EQ(breakpointCounter_, 2);
|
||||
return true;
|
||||
};
|
||||
|
||||
loadModule = [this](std::string_view moduleName) {
|
||||
if (flag_) {
|
||||
if (moduleName != pandaFile_) {
|
||||
return true;
|
||||
}
|
||||
flag_ = false;
|
||||
ASSERT_SUCCESS(debugInterface_->SetBreakpoint(locationEnd_));
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
breakpoint = [this](PtThread, const PtLocation &location) {
|
||||
ASSERT_TRUE(location.GetMethodId().IsValid());
|
||||
ASSERT_LOCATION_EQ(location, locationEnd_);
|
||||
// Check what step signalled before breakpoint
|
||||
ASSERT_LOCATION_EQ(location, locationStep_);
|
||||
ASSERT_TRUE(collectSteps_);
|
||||
breakpointCounter_++;
|
||||
// Disable collect steps
|
||||
collectSteps_ = false;
|
||||
return true;
|
||||
};
|
||||
|
||||
singleStep = [this](PtThread, const PtLocation &location) {
|
||||
ASSERT_TRUE(location.GetMethodId().IsValid());
|
||||
if (!collectSteps_) {
|
||||
if (locationStart_ == location) {
|
||||
collectSteps_ = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
ASSERT_NE(bytecodeOffset_, location.GetBytecodeOffset());
|
||||
locationStep_ = location;
|
||||
stepCounter_++;
|
||||
bytecodeOffset_ = location.GetBytecodeOffset();
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
std::pair<CString, CString> GetEntryPoint() override
|
||||
{
|
||||
return {pandaFile_, entryPoint_};
|
||||
}
|
||||
|
||||
private:
|
||||
CString pandaFile_ = "/data/test/Sample.abc";
|
||||
CString entryPoint_ = "_GLOBAL::func_main_0";
|
||||
PtLocation locationStart_ {nullptr, PtLocation::EntityId(0), 0};
|
||||
PtLocation locationEnd_ {nullptr, PtLocation::EntityId(0), 0};
|
||||
PtLocation locationStep_ {nullptr, PtLocation::EntityId(0), 0};
|
||||
int32_t stepCounter_ = 0;
|
||||
int32_t breakpointCounter_ = 0;
|
||||
bool collectSteps_ = false;
|
||||
uint32_t bytecodeOffset_ = std::numeric_limits<uint32_t>::max();
|
||||
bool flag_ = true;
|
||||
};
|
||||
|
||||
std::unique_ptr<TestEvents> GetJsSingleStepTest()
|
||||
{
|
||||
return std::make_unique<JsSingleStepTest>();
|
||||
}
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_SINGLE_STEP_TEST_H
|
@ -13,15 +13,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ecmascript/tooling/test/test_list.h"
|
||||
#include "ecmascript/tooling/test/api_tests/api_tests.h"
|
||||
#include "ecmascript/tooling/test/test_util.h"
|
||||
#include "ecmascript/tooling/test/utils/testcases/test_list.h"
|
||||
|
||||
#include "ecmascript/tooling/test/utils/test_util.h"
|
||||
|
||||
// testcase list
|
||||
#include "js_breakpoint_test.h"
|
||||
#include "js_single_step_test.h"
|
||||
|
||||
namespace panda::tooling::ecmascript::test {
|
||||
static const char *g_currentTestName = nullptr;
|
||||
|
||||
static void RegisterTests()
|
||||
{
|
||||
// Register testcases
|
||||
TestUtil::RegisterTest(panda_file::SourceLang::ECMASCRIPT, "JsBreakpoint", GetJsBreakpointTest());
|
||||
TestUtil::RegisterTest(panda_file::SourceLang::ECMASCRIPT, "JsSingleStepTest", GetJsSingleStepTest());
|
||||
}
|
@ -13,8 +13,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_TEST_LIST_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_TEST_LIST_H
|
||||
#ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_TEST_LIST_H
|
||||
#define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_TEST_LIST_H
|
||||
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@ -28,8 +28,9 @@ using panda::ecmascript::CString;
|
||||
std::vector<const char *> GetTestList(panda_file::SourceLang language);
|
||||
|
||||
void SetCurrentTestName(const char *testName);
|
||||
const char *GetCurrentTestName();
|
||||
|
||||
std::pair<CString, CString> GetTestEntryPoint(const char *testName);
|
||||
} // namespace panda::tooling::ecmascript::test
|
||||
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_TEST_LIST_H
|
||||
#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_TEST_LIST_H
|
@ -15,8 +15,9 @@
|
||||
<configuration ver="2.0">
|
||||
<target name="EcmaDebugApiTest">
|
||||
<preparer>
|
||||
<option name="push" value="obj/ark/js_runtime/ecmascript/tooling/test/Sample.abc -> /data/app" src="out"/>
|
||||
<option name="push" value="obj/ark/js_runtime/ecmascript/tooling/test/Sample.abc -> /data/test" src="out"/>
|
||||
<option name="push" value="test/test/libjsdebugtest.so -> /data/test" src="out"/>
|
||||
<option name="push" value="test/test/libdebugger_entry.so -> /data/test" src="out"/>
|
||||
</preparer>
|
||||
</target>
|
||||
<target name="DebuggerCommandsTest">
|
||||
|
Loading…
Reference in New Issue
Block a user