diff --git a/BUILD.gn b/BUILD.gn index af617fdbf966606aae5a09f874bb245fd6b686ba..d31179db3d96b2655d5c0c9075f536c3abf0bf98 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -338,8 +338,10 @@ ecma_source = [ "ecmascript/interpreter/slow_runtime_helper.cpp", "ecmascript/interpreter/slow_runtime_stub.cpp", "ecmascript/jobs/micro_job_queue.cpp", + "ecmascript/jspandafile/debug_info_extractor.cpp", "ecmascript/jspandafile/js_pandafile.cpp", "ecmascript/jspandafile/js_pandafile_manager.cpp", + "ecmascript/jspandafile/scope_info_extractor.cpp", "ecmascript/js_api_tree_map.cpp", "ecmascript/js_api_tree_map_iterator.cpp", "ecmascript/js_api_tree_set.cpp", @@ -415,7 +417,6 @@ ecma_source = [ "ecmascript/regexp/regexp_parser_cache.cpp", "ecmascript/runtime_api.cpp", "ecmascript/runtime_trampolines.cpp", - "ecmascript/scope_info_extractor.cpp", "ecmascript/snapshot/mem/slot_bit.cpp", "ecmascript/snapshot/mem/snapshot.cpp", "ecmascript/snapshot/mem/snapshot_serialize.cpp", @@ -435,8 +436,8 @@ ecma_source = [ ] ecma_source += [ - "ecmascript/tooling/interface/debugger_api.cpp", - "ecmascript/tooling/interface/js_debugger.cpp", + "ecmascript/tooling/backend/debugger_api.cpp", + "ecmascript/tooling/backend/js_debugger.cpp", ] if (current_cpu == "arm") { @@ -447,7 +448,7 @@ if (current_cpu == "arm") { current_cpu == "x86_64") { ecma_source += [ "ecmascript/trampoline/call_trampoline_amd64.S" ] } -source_set("libark_jsruntime_static") { +source_set("libark_jsruntime_set") { sources = ecma_source public_configs = [ @@ -479,7 +480,7 @@ source_set("libark_jsruntime_static") { ohos_shared_library("libark_jsruntime") { deps = [ ":libark_js_intl_static", - ":libark_jsruntime_static", + ":libark_jsruntime_set", ] if (!is_linux) { @@ -503,7 +504,7 @@ ohos_shared_library("libark_jsruntime") { subsystem_name = "ark" } -source_set("libark_jsruntime_test_static") { +source_set("libark_jsruntime_test_set") { sources = ecma_source sources += intl_sources @@ -537,7 +538,7 @@ ohos_shared_library("libark_jsruntime_test") { "$ark_root/runtime:arkruntime_public_config", ] - deps = [ ":libark_jsruntime_test_static" ] + deps = [ ":libark_jsruntime_test_set" ] if (!is_linux) { if (build_public_version) { diff --git a/ecmascript/base/error_helper.cpp b/ecmascript/base/error_helper.cpp index f6799bf3275d9b1e667d6b2668c903ef743d7b08..c2fdbe95ec6e487a8037c65b95707b8361975555 100644 --- a/ecmascript/base/error_helper.cpp +++ b/ecmascript/base/error_helper.cpp @@ -23,11 +23,12 @@ #include "ecmascript/interpreter/interpreter.h" #include "ecmascript/js_object-inl.h" #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/backend/js_pt_extractor.h" namespace panda::ecmascript::base { -using panda::ecmascript::tooling::PtJSExtractor; +using panda::ecmascript::tooling::JSPtExtractor; JSTaggedValue ErrorHelper::ErrorCommonToString(EcmaRuntimeCallInfo *argv, const ErrorType &errorType) { @@ -172,7 +173,7 @@ JSTaggedValue ErrorHelper::ErrorCommonConstructor(EcmaRuntimeCallInfo *argv, return nativeInstanceObj.GetTaggedValue(); } -CString ErrorHelper::DecodeFunctionName(const CString &name) +std::string ErrorHelper::DecodeFunctionName(const std::string &name) { if (name.empty()) { return "anonymous"; @@ -182,16 +183,15 @@ CString ErrorHelper::DecodeFunctionName(const CString &name) JSHandle ErrorHelper::BuildEcmaStackTrace(JSThread *thread) { - CString data = BuildNativeEcmaStackTrace(thread); + std::string data = BuildNativeEcmaStackTrace(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); LOG(DEBUG, ECMASCRIPT) << data; - return factory->NewFromString(data); + return factory->NewFromStdString(data); } -CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread) +std::string ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread) { - auto ecmaVm = thread->GetEcmaVM(); - CString data; + std::string data; auto sp = const_cast(thread->GetCurrentSPFrame()); InterpretedFrameHandler frameHandler(sp); for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) { @@ -204,8 +204,9 @@ CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread) data += DecodeFunctionName(method->ParseFunctionName()); data.append(" ("); // source file - PtJSExtractor *debugExtractor = ecmaVm->GetDebugInfoExtractor(method->GetPandaFile()); - const CString &sourceFile = debugExtractor->GetSourceFile(method->GetFileId()); + tooling::JSPtExtractor *debugExtractor = + JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile()); + const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetFileId()); if (sourceFile.empty()) { data.push_back('?'); } else { @@ -213,13 +214,19 @@ CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread) } data.push_back(':'); // line number and column number - auto callbackFunc = [&data](size_t line, size_t column) -> bool { - data += ToCString(static_cast(line) + 1); + auto callbackLineFunc = [&data](int32_t line) -> bool { + data += ToCString(line + 1); data.push_back(':'); - data += ToCString(static_cast(column) + 1); return true; }; - if (!debugExtractor->MatchWithOffset(callbackFunc, method->GetFileId(), frameHandler.GetBytecodeOffset())) { + auto callbackColumnFunc = [&data](int32_t column) -> bool { + data += ToCString(column + 1); + return true; + }; + panda_file::File::EntityId methodId = method->GetFileId(); + uint32_t offset = frameHandler.GetBytecodeOffset(); + if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) || + !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) { data.push_back('?'); } data.push_back(')'); @@ -230,9 +237,9 @@ CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread) return data; } -CString ErrorHelper::BuildNativeAndJsStackTrace(JSThread *thread) +std::string ErrorHelper::BuildNativeAndJsStackTrace(JSThread *thread) { - CString stack = BuildNativeEcmaStackTrace(thread); + std::string stack = BuildNativeEcmaStackTrace(thread); return stack; } } // namespace panda::ecmascript::base diff --git a/ecmascript/base/error_helper.h b/ecmascript/base/error_helper.h index 4d998d38504690d6567f5aa06a3f82efbb477b49..0a4edf0050b84cbb5c8e984838dd0b623a607be1 100644 --- a/ecmascript/base/error_helper.h +++ b/ecmascript/base/error_helper.h @@ -31,12 +31,12 @@ public: static JSTaggedValue ErrorCommonConstructor(EcmaRuntimeCallInfo *argv, const ErrorType &errorType); - static CString BuildNativeEcmaStackTrace(JSThread *thread); + static std::string BuildNativeEcmaStackTrace(JSThread *thread); - static CString BuildNativeAndJsStackTrace(JSThread *thread); + static std::string BuildNativeAndJsStackTrace(JSThread *thread); private: - static CString DecodeFunctionName(const CString &name); + static std::string DecodeFunctionName(const std::string &name); static JSHandle BuildEcmaStackTrace(JSThread *thread); static JSHandle GetErrorName(JSThread *thread, const JSHandle &name, diff --git a/ecmascript/class_info_extractor.cpp b/ecmascript/class_info_extractor.cpp index febd3d2c22c3a146236ca7066b2d40eb696c7a0d..962680012baf7a26e72d5a7abd5977d68c911e5b 100644 --- a/ecmascript/class_info_extractor.cpp +++ b/ecmascript/class_info_extractor.cpp @@ -82,8 +82,8 @@ void ClassInfoExtractor::BuildClassInfoExtractorFromLiteral(JSThread *thread, JS } } else { // without static properties, set class name - CString clsName = extractor->GetConstructorMethod()->ParseFunctionName(); - JSHandle clsNameHandle = factory->NewFromString(clsName.c_str()); + std::string clsName = extractor->GetConstructorMethod()->ParseFunctionName(); + JSHandle clsNameHandle = factory->NewFromStdString(clsName); staticProperties->Set(thread, NAME_INDEX, clsNameHandle); } @@ -150,8 +150,8 @@ bool ClassInfoExtractor::ExtractAndReturnWhetherWithElements(JSThread *thread, c if (LIKELY(!keysHasNameFlag)) { [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - CString clsName = detail.ctorMethod->ParseFunctionName(); - JSHandle clsNameHandle = factory->NewFromString(clsName.c_str()); + std::string clsName = detail.ctorMethod->ParseFunctionName(); + JSHandle clsNameHandle = factory->NewFromStdString(clsName); properties->Set(thread, NAME_INDEX, clsNameHandle); } else { // class has static name property, reserved length bigger 1 than actual, need trim diff --git a/ecmascript/class_linker/panda_file_translator.cpp b/ecmascript/class_linker/panda_file_translator.cpp index 6aa883ef3b8db6e243e79e3ace6b976e51c8fe9b..7173fd9afc48a313e5cf03e0b203053d8c45a6df 100644 --- a/ecmascript/class_linker/panda_file_translator.cpp +++ b/ecmascript/class_linker/panda_file_translator.cpp @@ -20,7 +20,7 @@ #include #include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/global_env.h" #include "ecmascript/interpreter/interpreter.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" @@ -93,8 +93,7 @@ void PandaFileTranslator::TranslateClasses(JSPandaFile *jsPandaFile, const CStri jsPandaFile->UpdateMainMethodIndex(mda.GetMethodId().GetOffset()); } - panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId()); - InitializeMemory(method, nullptr, pf, mda.GetMethodId(), codeDataAccessor.GetCodeId(), + InitializeMemory(method, jsPandaFile, mda.GetMethodId(), codeDataAccessor.GetCodeId(), mda.GetAccessFlags(), codeDataAccessor.GetNumArgs(), nullptr); method->SetHotnessCounter(EcmaInterpreter::METHOD_HOTNESS_THRESHOLD); method->InitializeCallField(); @@ -251,7 +250,7 @@ Program *PandaFileTranslator::GenerateProgram() } JSHandle jsPandaFilePointer = factory_->NewJSNativePointer( const_cast(jsPandaFile_), JSPandaFileManager::RemoveJSPandaFile, - EcmaVM::GetJSPandaFileManager()); + JSPandaFileManager::GetInstance()); constpool->Set(thread_, constpoolIndex, jsPandaFilePointer.GetTaggedValue()); DefineClassInConstPool(constpool); diff --git a/ecmascript/compiler/BUILD.gn b/ecmascript/compiler/BUILD.gn index 430670f1102e1d9020d07ffe9e1f168789f1599a..203a4127118f1ff8e06d091212cac17b72fb3390 100644 --- a/ecmascript/compiler/BUILD.gn +++ b/ecmascript/compiler/BUILD.gn @@ -161,7 +161,7 @@ ohos_shared_library("libark_jsoptimizer") { ohos_shared_library("libark_jsoptimizer_test") { deps = [ ":libark_jsoptimizer_static", - "//ark/js_runtime:libark_jsruntime_test_static", + "//ark/js_runtime:libark_jsruntime_test_set", ] if (is_standard_system) { diff --git a/ecmascript/compiler/tests/BUILD.gn b/ecmascript/compiler/tests/BUILD.gn index 5268dae914decba60e314dc37f00abe35926acc5..66f942dce3002a3d1eecc9149ed8bcb13bf6b909 100644 --- a/ecmascript/compiler/tests/BUILD.gn +++ b/ecmascript/compiler/tests/BUILD.gn @@ -122,5 +122,5 @@ group("host_unittest") { testonly = true # deps file - deps = [ ":StubTestAction" ] + # deps = [ ":StubTestAction" ] } diff --git a/ecmascript/cpu_profiler/cpu_profiler.cpp b/ecmascript/cpu_profiler/cpu_profiler.cpp index 1f6544b81b9451fcd392425068f5441ce4764b97..b8f8f0e3003c5688439bbf27764cbf2296ffd90f 100644 --- a/ecmascript/cpu_profiler/cpu_profiler.cpp +++ b/ecmascript/cpu_profiler/cpu_profiler.cpp @@ -19,7 +19,9 @@ #include #include #include +#include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/platform/platform.h" + namespace panda::ecmascript { CMap CpuProfiler::staticStackInfo_ = CMap(); std::atomic CpuProfiler::singleton_ = nullptr; @@ -189,25 +191,25 @@ void CpuProfiler::GetFrameStack(JSThread *thread) void CpuProfiler::ParseMethodInfo(JSMethod *method, JSThread *thread, InterpretedFrameHandler frameHandler) { struct StackInfo codeEntry; - auto ecmaVm = thread->GetEcmaVM(); if (method != nullptr && method->IsNative()) { codeEntry.codeType = "other"; codeEntry.functionName = "native"; staticStackInfo_.insert(std::make_pair(method, codeEntry)); } else { codeEntry.codeType = "JS"; - const CString &functionName = method->ParseFunctionName(); + const std::string &functionName = method->ParseFunctionName(); if (functionName.empty()) { codeEntry.functionName = "anonymous"; } else { codeEntry.functionName = functionName.c_str(); } // source file - tooling::PtJSExtractor *debugExtractor = ecmaVm->GetDebugInfoExtractor(method->GetPandaFile()); + tooling::JSPtExtractor *debugExtractor = + JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile()); if (method == nullptr) { return; } - const CString &sourceFile = debugExtractor->GetSourceFile(method->GetFileId()); + const std::string &sourceFile = debugExtractor->GetSourceFile(method->GetFileId()); if (sourceFile.empty()) { codeEntry.url = ""; } else { @@ -221,15 +223,25 @@ void CpuProfiler::ParseMethodInfo(JSMethod *method, JSThread *thread, Interprete } } // line number - int lineNumber = 0; - auto callbackFunc = [&](size_t line, [[maybe_unused]] size_t column) -> bool { + int32_t lineNumber = 0; + int32_t columnNumber = 0; + auto callbackLineFunc = [&](int32_t line) -> bool { lineNumber = line + 1; return true; }; - if (!debugExtractor->MatchWithOffset(callbackFunc, method->GetFileId(), frameHandler.GetBytecodeOffset())) { + auto callbackColumnFunc = [&](int32_t column) -> bool { + columnNumber = column + 1; + return true; + }; + panda_file::File::EntityId methodId = method->GetFileId(); + uint32_t offset = frameHandler.GetBytecodeOffset(); + if (!debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) || + !debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) { codeEntry.lineNumber = 0; + codeEntry.columnNumber = 0; } else { codeEntry.lineNumber = lineNumber; + codeEntry.columnNumber = columnNumber; } staticStackInfo_.insert(std::make_pair(method, codeEntry)); } diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index c33d948707dc88cf0e614b90dc2562763cb8d5fa..ff9849ac57f264efebe0d86a62b4f55f1e85cc2b 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -20,7 +20,7 @@ #include "ecmascript/accessor_data.h" #include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_dictionary-inl.h" diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index 0e165d5911e0ccc72983779fd411e7c50bf01d7b..4cddf0f7c7b5ee8dc236295991bc8c463aa53e5e 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -19,7 +19,7 @@ #include "ecmascript/builtins.h" #include "ecmascript/builtins/builtins_regexp.h" #include "ecmascript/class_linker/panda_file_translator.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/cpu_profiler/cpu_profiler.h" #include "ecmascript/ecma_module.h" #include "ecmascript/ecma_string_table.h" @@ -183,7 +183,7 @@ bool EcmaVM::Initialize() LOG_ECMA(DEBUG) << "EcmaVM::Initialize run snapshot"; SnapShot snapShot(this); std::unique_ptr pf = snapShot.DeserializeGlobalEnvAndProgram(snapshotFileName_); - frameworkPandaFile_ = GetJSPandaFileManager()->CreateJSPandaFile(pf.release(), frameworkAbcFileName_); + frameworkPandaFile_ = JSPandaFileManager::GetInstance()->CreateJSPandaFile(pf.release(), frameworkAbcFileName_); globalConst->InitGlobalUndefined(); } @@ -195,12 +195,6 @@ bool EcmaVM::Initialize() return true; } -JSPandaFileManager *EcmaVM::GetJSPandaFileManager() -{ - static JSPandaFileManager jsFileManager; - return &jsFileManager; -} - void EcmaVM::InitializeEcmaScriptRunStat() { // NOLINTNEXTLINE(modernize-avoid-c-arrays) @@ -323,7 +317,7 @@ bool EcmaVM::ExecuteFromPf(const std::string &filename, std::string_view entryPo { const JSPandaFile *jsPandaFile = nullptr; if (frameworkPandaFile_ == nullptr || !IsFrameworkPandaFile(filename)) { - jsPandaFile = GetJSPandaFileManager()->LoadPfAbc(filename); + jsPandaFile = JSPandaFileManager::GetInstance()->LoadPfAbc(filename); if (jsPandaFile == nullptr) { return false; } @@ -338,7 +332,7 @@ bool EcmaVM::CollectInfoOfPandaFile(const std::string &filename, std::string_vie { const JSPandaFile *jsPandaFile; if (frameworkPandaFile_ == nullptr || !IsFrameworkPandaFile(filename)) { - jsPandaFile = GetJSPandaFileManager()->LoadPfAbc(filename); + jsPandaFile = JSPandaFileManager::GetInstance()->LoadPfAbc(filename); if (jsPandaFile == nullptr) { return false; } @@ -369,7 +363,7 @@ bool EcmaVM::ExecuteFromBuffer(const void *buffer, size_t size, std::string_view return false; } CString methodName(entryPoint.substr(pos + 1)); - const JSPandaFile *jsPandaFile = GetJSPandaFileManager()->LoadBufferAbc(filename, buffer, size); + const JSPandaFile *jsPandaFile = JSPandaFileManager::GetInstance()->LoadBufferAbc(filename, buffer, size); if (jsPandaFile == nullptr) { return false; } @@ -377,12 +371,6 @@ bool EcmaVM::ExecuteFromBuffer(const void *buffer, size_t size, std::string_view return true; } -tooling::PtJSExtractor *EcmaVM::GetDebugInfoExtractor(const panda_file::File *file) -{ - tooling::PtJSExtractor *res = GetJSPandaFileManager()->GetOrCreatePtJSExtractor(file); - return res; -} - bool EcmaVM::Execute(const JSPandaFile *jsPandaFile, std::string_view entryPoint, const std::vector &args) { // Get ClassName and MethodName @@ -413,7 +401,7 @@ JSMethod *EcmaVM::GetMethodForNativeFunction(const void *func) uint32_t accessFlags = ACC_PUBLIC | ACC_STATIC | ACC_FINAL | ACC_NATIVE; uint32_t numArgs = 2; // function object and this - auto method = chunk_.New(nullptr, nullptr, panda_file::File::EntityId(0), panda_file::File::EntityId(0), + auto method = chunk_.New(nullptr, panda_file::File::EntityId(0), panda_file::File::EntityId(0), accessFlags, numArgs, nullptr); method->SetNativePointer(const_cast(func)); method->SetNativeBit(true); @@ -450,7 +438,7 @@ Expected EcmaVM::InvokeEntrypointImpl(Method *entrypoint, c { // For testcase startup const panda_file::File *file = entrypoint->GetPandaFile(); - const JSPandaFile *jsPandaFile = GetJSPandaFileManager()->GetJSPandaFile(file); + const JSPandaFile *jsPandaFile = JSPandaFileManager::GetInstance()->GetJSPandaFile(file); ASSERT(jsPandaFile != nullptr); return InvokeEcmaEntrypoint(jsPandaFile, utf::Mutf8AsCString(entrypoint->GetName().data), args); } @@ -462,7 +450,7 @@ Expected EcmaVM::InvokeEcmaEntrypoint(const JSPandaFile *js [[maybe_unused]] EcmaHandleScope scope(thread_); JSHandle program; if (snapshotSerializeEnable_) { - program = GetJSPandaFileManager()->GenerateProgram(this, jsPandaFile); + program = JSPandaFileManager::GetInstance()->GenerateProgram(this, jsPandaFile); auto index = jsPandaFile->GetJSPandaFileDesc().find(frameworkAbcFileName_); if (index != CString::npos) { @@ -472,7 +460,7 @@ Expected EcmaVM::InvokeEcmaEntrypoint(const JSPandaFile *js } } else { if (jsPandaFile != frameworkPandaFile_) { - program = GetJSPandaFileManager()->GenerateProgram(this, jsPandaFile); + program = JSPandaFileManager::GetInstance()->GenerateProgram(this, jsPandaFile); } else { program = JSHandle(thread_, frameworkProgram_); RedirectMethod(*jsPandaFile->GetPandaFile()); @@ -742,7 +730,7 @@ JSHandle EcmaVM::GetModuleByName(JSHandle moduleNa { // only used in testcase, pandaFileWithProgram_ only one item. this interface will delete const JSPandaFile *currentJSPandaFile = nullptr; - GetJSPandaFileManager()->EnumerateJSPandaFiles([¤tJSPandaFile](const JSPandaFile *jsPandaFile) { + JSPandaFileManager::GetInstance()->EnumerateJSPandaFiles([¤tJSPandaFile](const JSPandaFile *jsPandaFile) { currentJSPandaFile = jsPandaFile; return false; }); diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index f680fc46edb378ad8bb1a78341ee60ee536ed9bc..2ef8f9185f50cef53a238e244791973fb0a42e7a 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -34,7 +34,7 @@ #include "ecmascript/platform/task.h" #include "ecmascript/snapshot/mem/snapshot_serialize.h" #include "ecmascript/tooling/interface/js_debugger_manager.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/backend/js_pt_extractor.h" #include "include/panda_vm.h" #include "libpandabase/macros.h" @@ -82,8 +82,6 @@ using HostPromiseRejectionTracker = void (*)(const EcmaVM* vm, using PromiseRejectCallback = void (*)(void* info); class EcmaVM : public PandaVM { - using PtJSExtractor = tooling::PtJSExtractor; - public: static EcmaVM *Cast(PandaVM *object) { @@ -112,8 +110,6 @@ public: std::vector *infoList, const panda_file::File *&pf); - PtJSExtractor *GetDebugInfoExtractor(const panda_file::File *file); - bool IsInitialized() const { return vmInitialized_; @@ -401,8 +397,6 @@ public: } } - static JSPandaFileManager *GetJSPandaFileManager(); - void SetConstpool(const JSPandaFile *jsPandaFile, JSTaggedValue constpool); JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile); @@ -449,7 +443,7 @@ private: bool isTestMode_ {false}; // VM startup states. - static JSRuntimeOptions options_; + PUBLIC_API static JSRuntimeOptions options_; bool icEnable_ {true}; bool vmInitialized_ {false}; GCStats *gcStats_ {nullptr}; diff --git a/ecmascript/global_env.cpp b/ecmascript/global_env.cpp index cf6b5ef8285f39b4de56ef53b8d5c7bec5e25831..65790936f042d0524ae9236252ba9bf8e9af302b 100644 --- a/ecmascript/global_env.cpp +++ b/ecmascript/global_env.cpp @@ -16,7 +16,7 @@ #include "ecmascript/global_env.h" #include "ecma_module.h" #include "ecmascript/builtins/builtins_promise_handler.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/ic/ic_handler.h" #include "ecmascript/ic/proto_change_details.h" #include "ecmascript/jobs/micro_job_queue.h" diff --git a/ecmascript/global_env_constants.cpp b/ecmascript/global_env_constants.cpp index 8980d0eb9bb6a1166beda2b070745494b722216a..d8f868a88368c4197f880247709733f0d91b554d 100644 --- a/ecmascript/global_env_constants.cpp +++ b/ecmascript/global_env_constants.cpp @@ -19,7 +19,7 @@ #include "ecmascript/builtins.h" #include "ecmascript/builtins/builtins_global.h" #include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/free_object.h" diff --git a/ecmascript/hprof/tests/hprof_test.cpp b/ecmascript/hprof/tests/hprof_test.cpp index c50ebee7fc55432f50d19836178b8bb3bc24822b..14ce560749d35c66af1d0268bc7cf23caad98e44 100644 --- a/ecmascript/hprof/tests/hprof_test.cpp +++ b/ecmascript/hprof/tests/hprof_test.cpp @@ -17,7 +17,7 @@ #include #include "ecmascript/accessor_data.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_dictionary-inl.h" diff --git a/ecmascript/interpreter/frame_handler.cpp b/ecmascript/interpreter/frame_handler.cpp index 0987af7a3b7034e167588f41c43a6c0f0194caf6..0abb2e0353cba4c9c7a3ceac4b1e93b71c62fafc 100644 --- a/ecmascript/interpreter/frame_handler.cpp +++ b/ecmascript/interpreter/frame_handler.cpp @@ -16,7 +16,7 @@ #include "ecmascript/interpreter/frame_handler.h" -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/compiler/llvm/llvm_stackmap_parser.h" #include "ecmascript/mem/heap.h" #include "ecmascript/js_function.h" diff --git a/ecmascript/interpreter/frame_handler.h b/ecmascript/interpreter/frame_handler.h index 4b0a9390a755cc6240731967ff7adec8e10a7106..8f1948c617e4895db1a5bd46bbba66e802c2a35e 100644 --- a/ecmascript/interpreter/frame_handler.h +++ b/ecmascript/interpreter/frame_handler.h @@ -31,6 +31,8 @@ class ConstantPool; class FrameHandler { public: + explicit FrameHandler(const JSThread *thread) + : sp_(const_cast(thread->GetCurrentSPFrame())) {} explicit FrameHandler(JSTaggedType *sp) : sp_(sp) {} ~FrameHandler() = default; DEFAULT_COPY_SEMANTIC(FrameHandler); diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index becf5130efcda523bca6c6b501ec9bab3a37194e..816101901682d53387b6caa0207ffd0ad1b7ea0d 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -16,9 +16,9 @@ #ifndef ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H #define ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/cpu_profiler/cpu_profiler.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" @@ -136,6 +136,19 @@ namespace panda::ecmascript { RESTORE_ACC(); \ } while (false) +/* + * reasons of set acc with hole: + * 1. acc will become illegal when new error + * 2. debugger logic will save acc, so illegal acc will set to frame + * 3. when debugger trigger gc, will mark an invalid acc and crash + * 4. acc will set to exception later, so it can set to hole template + */ +#define NOTIFY_DEBUGGER_EXCEPTION_EVENT() \ + do { \ + SET_ACC(JSTaggedValue::Hole()); \ + NOTIFY_DEBUGGER_EVENT(); \ + } while (false) + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define CALL_INITIALIZE() \ do { \ diff --git a/ecmascript/interpreter/interpreter_assembly.cpp b/ecmascript/interpreter/interpreter_assembly.cpp index 3ac8bfa87725a44b2b0e4c312e4318ba910904cf..0bd85e8e8c82aa85223c33310ee3f63fabc3e2dd 100644 --- a/ecmascript/interpreter/interpreter_assembly.cpp +++ b/ecmascript/interpreter/interpreter_assembly.cpp @@ -15,7 +15,7 @@ #include "ecmascript/interpreter/interpreter_assembly.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" diff --git a/ecmascript/interpreter/slow_runtime_stub.cpp b/ecmascript/interpreter/slow_runtime_stub.cpp index 503362acdf613e238d184b038119ce43231b8ef8..3ec65b51f8c710d1dd39e0b7cf799c5c608e2161 100644 --- a/ecmascript/interpreter/slow_runtime_stub.cpp +++ b/ecmascript/interpreter/slow_runtime_stub.cpp @@ -17,7 +17,7 @@ #include "ecmascript/base/number_helper.h" #include "ecmascript/builtins/builtins_regexp.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/ecma_module.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/ic/profile_type_info.h" @@ -39,7 +39,7 @@ #include "ecmascript/js_proxy.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" -#include "ecmascript/scope_info_extractor.h" +#include "ecmascript/jspandafile/scope_info_extractor.h" #include "ecmascript/tagged_dictionary.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/template_string.h" diff --git a/ecmascript/interpreter/slow_runtime_stub.h b/ecmascript/interpreter/slow_runtime_stub.h index 251a932321bc2fd53adc794b7fde36e115adfd8f..a97ee9e1c9d48bc480c8a34dd1d7d590a9ccc88b 100644 --- a/ecmascript/interpreter/slow_runtime_stub.h +++ b/ecmascript/interpreter/slow_runtime_stub.h @@ -16,7 +16,7 @@ #ifndef ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H #define ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" diff --git a/ecmascript/interpreter/templates/debugger_instruction_handler.inl b/ecmascript/interpreter/templates/debugger_instruction_handler.inl index dd104e7a77ced508d67a7af92f65a7d1b9225787..2baba0d56113b66ffcb4d6d0e6893431211aac8c 100644 --- a/ecmascript/interpreter/templates/debugger_instruction_handler.inl +++ b/ecmascript/interpreter/templates/debugger_instruction_handler.inl @@ -775,7 +775,7 @@ } HANDLE_OPCODE(DEBUG_EXCEPTION_HANDLER) { - NOTIFY_DEBUGGER_EVENT(); + NOTIFY_DEBUGGER_EXCEPTION_EVENT(); REAL_GOTO_EXCEPTION_HANDLER(); } HANDLE_OPCODE(DEBUG_HANDLE_OVERFLOW) diff --git a/ecmascript/js_function.cpp b/ecmascript/js_function.cpp index e58ef0715c963ef23dfd061bb6e8510aaf11968f..b73ac7d0b41bed291a0aa54d3248b1a405060ac3 100644 --- a/ecmascript/js_function.cpp +++ b/ecmascript/js_function.cpp @@ -145,7 +145,7 @@ JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle if (target->GetPandaFile() == nullptr) { return JSTaggedValue::Undefined(); } - CString funcName = target->ParseFunctionName(); + std::string funcName = target->ParseFunctionName(); if (funcName.empty()) { return thread->GlobalConstants()->GetEmptyString(); } @@ -157,7 +157,7 @@ JSTaggedValue JSFunction::NameGetter(JSThread *thread, const JSHandle } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - return factory->NewFromString(funcName).GetTaggedValue(); + return factory->NewFromStdString(funcName).GetTaggedValue(); } bool JSFunction::OrdinaryHasInstance(JSThread *thread, const JSHandle &constructor, diff --git a/ecmascript/js_method.cpp b/ecmascript/js_method.cpp index da1b6637e92a748970dd744f49d10457c073e20c..6d97ba687a8ffbd5581c5d36261afafa733fa716 100644 --- a/ecmascript/js_method.cpp +++ b/ecmascript/js_method.cpp @@ -14,18 +14,29 @@ */ #include "js_method.h" +#include "ecmascript/jspandafile/js_pandafile.h" #include "libpandafile/method_data_accessor-inl.h" namespace panda::ecmascript { +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(nullptr, jsPandaFile == nullptr ? nullptr : jsPandaFile->GetPandaFile(), + fileId, codeId, accessFlags, numArgs, shorty) +{ + bytecodeArray_ = JSMethod::GetInstructions(); + bytecodeArraySize_ = JSMethod::GetCodeSize(); + jsPandaFile_ = jsPandaFile; +} + // It's not allowed '#' token appear in ECMA function(method) name, which discriminates same names in panda methods. -CString JSMethod::ParseFunctionName() const +std::string JSMethod::ParseFunctionName() const { - CString methodName(utf::Mutf8AsCString(GetName().data)); + std::string methodName(utf::Mutf8AsCString(GetName().data)); if (LIKELY(methodName[0] != '#')) { return methodName; } size_t index = methodName.find_last_of('#'); - return CString(methodName.substr(index + 1)); + return methodName.substr(index + 1); } void JSMethod::InitializeCallField() diff --git a/ecmascript/js_method.h b/ecmascript/js_method.h index cba6475075f65b2d855853ceae7332f1fdf32ec6..c85319cedb61fd4d33af07d82f3de9c29e779630 100755 --- a/ecmascript/js_method.h +++ b/ecmascript/js_method.h @@ -20,10 +20,6 @@ #include "include/method.h" #include "libpandafile/file.h" -namespace panda { -class Class; -} - static constexpr uint32_t CALL_TYPE_MASK = 0xF; // 0xF: the last 4 bits are used as callType static constexpr size_t STORAGE_32_NUM = 4; static constexpr size_t STORAGE_PTR_NUM = 3; @@ -49,6 +45,8 @@ JS_METHOD_OFFSET_LIST(JS_METHOD_OFFSET_MACRO) #undef JS_METHOD_OFFSET_MACRO namespace panda::ecmascript { +class JSPandaFile; + class JSMethod : public Method { public: static constexpr uint8_t MAX_SLOT_SIZE = 0xFF; @@ -59,14 +57,8 @@ public: return static_cast(method); } - explicit JSMethod(Class *klass, const panda_file::File *pf, panda_file::File::EntityId fileId, - panda_file::File::EntityId codeId, uint32_t accessFlags, uint32_t numArgs, const uint16_t *shorty) - : Method(klass, pf, fileId, codeId, accessFlags, numArgs, shorty) - { - bytecodeArray_ = JSMethod::GetInstructions(); - bytecodeArraySize_ = JSMethod::GetCodeSize(); - } - + JSMethod(const JSPandaFile *jsPandaFile, panda_file::File::EntityId fileId, + panda_file::File::EntityId codeId, uint32_t accessFlags, uint32_t numArgs, const uint16_t *shorty); JSMethod() = delete; ~JSMethod() = default; JSMethod(const JSMethod &) = delete; @@ -136,7 +128,7 @@ public: callField_ = IsNativeBit::Update(callField_, isNative); } - CString ParseFunctionName() const; + std::string ParseFunctionName() const; void InitializeCallField(); bool HaveThisWithCallField() const @@ -178,12 +170,21 @@ public: { return NumArgsBits::Decode(callField_); } + panda_file::File::EntityId GetMethodId() const + { + return GetFileId(); + } + const JSPandaFile *GetJSPandaFile() const + { + return jsPandaFile_; + } private: const uint8_t *bytecodeArray_ {nullptr}; uint32_t bytecodeArraySize_ {0}; uint8_t slotSize_ {0}; uint64_t callField_ {0}; + const JSPandaFile *jsPandaFile_ {nullptr}; }; } // namespace panda::ecmascript diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index 36f05605995bd9e9444c47e90709c09fa34b0741..c8c73db5839bd184efb928c9cf6eb9dfa482414e 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -100,7 +100,7 @@ public: void Iterate(const RootVisitor &v0, const RootRangeVisitor &v1); - uintptr_t *ExpandHandleStorage(); + PUBLIC_API uintptr_t *ExpandHandleStorage(); void ShrinkHandleStorage(int prevIndex); JSTaggedType *GetHandleScopeStorageNext() const diff --git a/ecmascript/jspandafile/debug_info_extractor.cpp b/ecmascript/jspandafile/debug_info_extractor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6336248bc27e8bed84aefb4f9a7b3ecd0873ace2 --- /dev/null +++ b/ecmascript/jspandafile/debug_info_extractor.cpp @@ -0,0 +1,324 @@ +/* + * 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 "ecmascript/jspandafile/js_pandafile.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; + +static const char *GetStringFromConstantPool(const panda_file::File &pf, uint32_t offset) +{ + return reinterpret_cast(pf.GetStringData(panda_file::File::EntityId(offset)).data); +} + +DebugInfoExtractor::DebugInfoExtractor(const JSPandaFile *jsPandaFile) +{ + Extract(jsPandaFile->GetPandaFile()); +} + +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, PANDAFILE) << "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(); + } + } + + LineNumberTable GetLineNumberTable() const + { + return lnt_; + } + + ColumnNumberTable GetColumnNumberTable() const + { + return cnt_; + } + + LocalVariableTable GetLocalVariableTable() const + { + return lvt_; + } + + const uint8_t *GetFile() const + { + return state_.GetFile(); + } + + const uint8_t *GetSourceCode() const + { + return state_.GetSourceCode(); + } + +private: + using Opcode = LineNumberProgramItem::Opcode; + + Opcode ReadOpcode() + { + auto opcode = static_cast(*program_); + ++program_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return opcode; + } + + int32_t ReadRegisterNumber() + { + auto [regiserNumber, n, isFull] = leb128::DecodeSigned(program_); + LOG_IF(!isFull, FATAL, COMMON) << "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 typeSignature_index = state_.ReadULeb128(); + const char *name = GetStringFromConstantPool(state_.GetPandaFile(), nameIndex); + lvt_.insert(std::make_pair(name, regNumber)); + } + + void HandleEndLocal() + { + [[maybe_unused]] auto regNumber = ReadRegisterNumber(); + } + + void HandleSetColumn() + { + auto cn = state_.ReadULeb128(); + state_.SetColumn(cn); + cnt_.push_back({state_.GetAddress(), state_.GetColumn()}); + } + + void HandleSpecialOpcode(LineNumberProgramItem::Opcode opcode) + { + ASSERT(static_cast(opcode) >= LineNumberProgramItem::OPCODE_BASE); + + auto adjust_opcode = static_cast(static_cast(opcode) - LineNumberProgramItem::OPCODE_BASE); + auto pc_offset = static_cast(adjust_opcode / LineNumberProgramItem::LINE_RANGE); + int32_t line_offset = + static_cast(adjust_opcode) % LineNumberProgramItem::LINE_RANGE + LineNumberProgramItem::LINE_BASE; + state_.AdvancePc(pc_offset); + state_.AdvanceLine(line_offset); + 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 = reinterpret_cast(programProcessor.GetFile()); + const char *sourceCode = reinterpret_cast(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 std::string &DebugInfoExtractor::GetSourceFile(panda_file::File::EntityId methodId) const +{ + auto iter = methods_.find(methodId.GetOffset()); + if (iter == methods_.end()) { + LOG(FATAL, DEBUGGER) << "Get source file of unknown method id: " << methodId.GetOffset(); + } + return iter->second.sourceFile; +} + +const std::string &DebugInfoExtractor::GetSourceCode(panda_file::File::EntityId methodId) const +{ + auto iter = methods_.find(methodId.GetOffset()); + if (iter == methods_.end()) { + LOG(FATAL, DEBUGGER) << "Get source code of unknown method id: " << methodId.GetOffset(); + } + return iter->second.sourceCode; +} + +CVector DebugInfoExtractor::GetMethodIdList() const +{ + CVector list; + + for (const auto &method : methods_) { + list.push_back(panda_file::File::EntityId(method.first)); + } + return list; +} +} // namespace panda::ecmascript diff --git a/ecmascript/jspandafile/debug_info_extractor.h b/ecmascript/jspandafile/debug_info_extractor.h new file mode 100644 index 0000000000000000000000000000000000000000..ab67fa796cc11042aea78db37a8a88a4416ea7f9 --- /dev/null +++ b/ecmascript/jspandafile/debug_info_extractor.h @@ -0,0 +1,98 @@ +/* + * 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 "ecmascript/mem/c_containers.h" +#include "ecmascript/mem/c_string.h" +#include "ecmascript/common.h" +#include "libpandafile/file.h" + +namespace panda::ecmascript { +class JSPandaFile; + +struct LineTableEntry { + uint32_t offset; + int32_t line; + + bool operator<(const LineTableEntry &other) const + { + return offset < other.offset; + } +}; + +struct ColumnTableEntry { + uint32_t offset; + int32_t column; + + bool operator<(const ColumnTableEntry &other) const + { + return offset < other.offset; + } +}; + +using LineNumberTable = CVector; +using ColumnNumberTable = CVector; + +/* + * 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 = CUnorderedMap; // name, regNumber + +// public for debugger +class PUBLIC_API DebugInfoExtractor { +public: + explicit DebugInfoExtractor(const JSPandaFile *jsPandaFile); + + ~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 std::string &GetSourceFile(panda_file::File::EntityId methodId) const; + + const std::string &GetSourceCode(panda_file::File::EntityId methodId) const; + + CVector GetMethodIdList() const; + +private: + void Extract(const panda_file::File *pf); + + struct MethodDebugInfo { + std::string sourceFile; + std::string sourceCode; + LineNumberTable lineNumberTable; + ColumnNumberTable columnNumberTable; + LocalVariableTable localVariableTable; + }; + + CUnorderedMap methods_; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_JSPANDAFILE_DEBUG_INFO_EXTRACTOR_H diff --git a/ecmascript/jspandafile/js_pandafile.cpp b/ecmascript/jspandafile/js_pandafile.cpp index 454e8e31038b62718efe0bfa3edd927bb746f78a..3398906c5c538bbb7738df5f1c1630786e6179f9 100644 --- a/ecmascript/jspandafile/js_pandafile.cpp +++ b/ecmascript/jspandafile/js_pandafile.cpp @@ -15,7 +15,7 @@ #include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" namespace panda::ecmascript { JSPandaFile::JSPandaFile(const panda_file::File *pf, const CString &descriptor) : pf_(pf), desc_(descriptor) @@ -36,13 +36,13 @@ JSPandaFile::~JSPandaFile() } } -tooling::PtJSExtractor *JSPandaFile::GetOrCreatePtJSExtractor() +tooling::JSPtExtractor *JSPandaFile::GetJSPtExtractor() { - if (ptJSExtractor_) { - return ptJSExtractor_.get(); + if (JSPtExtractor_) { + return JSPtExtractor_.get(); } - ptJSExtractor_ = std::make_unique(pf_); - return ptJSExtractor_.get(); + JSPtExtractor_ = std::make_unique(this); + return JSPtExtractor_.get(); } uint32_t JSPandaFile::GetOrInsertConstantPool(ConstPoolType type, uint32_t offset) diff --git a/ecmascript/jspandafile/js_pandafile.h b/ecmascript/jspandafile/js_pandafile.h index ddc88728bed97707a640debccecc42e4e2e21847..dd1cca0eded5ed26d4eaa27fea11ee3182808d97 100644 --- a/ecmascript/jspandafile/js_pandafile.h +++ b/ecmascript/jspandafile/js_pandafile.h @@ -19,7 +19,7 @@ #include "ecmascript/class_linker/panda_file_translator.h" #include "ecmascript/jspandafile/constpool_value.h" #include "ecmascript/mem/c_containers.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/backend/js_pt_extractor.h" #include "libpandafile/file.h" #include "libpandabase/utils/logger.h" @@ -36,9 +36,9 @@ public: JSPandaFile(const panda_file::File *pf, const CString &descriptor); ~JSPandaFile(); - tooling::PtJSExtractor *GetOrCreatePtJSExtractor(); + tooling::JSPtExtractor *GetJSPtExtractor(); - CString GetJSPandaFileDesc() const + const CString &GetJSPandaFileDesc() const { return desc_; } @@ -104,7 +104,7 @@ private: JSMethod *methods_ {nullptr}; CUnorderedMap methodMap_; const panda_file::File *pf_ {nullptr}; - std::unique_ptr ptJSExtractor_; + std::unique_ptr JSPtExtractor_; CString desc_; }; } // namespace ecmascript diff --git a/ecmascript/jspandafile/js_pandafile_manager.cpp b/ecmascript/jspandafile/js_pandafile_manager.cpp index a309da632cb29a57e77beab2c3314ebd6ea099bd..814704cd07b45b1ab48a1a95a97327e8cf93fe15 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.cpp +++ b/ecmascript/jspandafile/js_pandafile_manager.cpp @@ -14,7 +14,7 @@ */ #include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" namespace panda::ecmascript { static const size_t MALLOC_SIZE_LIMIT = 2147483648; // Max internal memory used by the VM declared in options @@ -153,15 +153,12 @@ void JSPandaFileManager::ReleaseJSPandaFile(const JSPandaFile *jsPandaFile) delete jsPandaFile; } -tooling::PtJSExtractor *JSPandaFileManager::GetOrCreatePtJSExtractor(const panda_file::File *pf) +tooling::JSPtExtractor *JSPandaFileManager::GetJSPtExtractor(const JSPandaFile *pf) { - os::memory::LockHolder lock(jsPandaFileLock_); - const JSPandaFile *existJSPandaFile = GetJSPandaFile(pf); - if (existJSPandaFile == nullptr) { - LOG_ECMA(FATAL) << "can not get PtJSExtrjsPandaFile from unknown jsPandaFile"; + if (pf == nullptr) { return nullptr; } - return const_cast(existJSPandaFile)->GetOrCreatePtJSExtractor(); + return const_cast(pf)->GetJSPtExtractor(); } const JSPandaFile *JSPandaFileManager::CreateJSPandaFile(const panda_file::File *pf, const CString &desc) diff --git a/ecmascript/jspandafile/js_pandafile_manager.h b/ecmascript/jspandafile/js_pandafile_manager.h index b78856098fae3a635eecbd95b5fa53048ec32379..d4af32e5d576f222e888e0cbc53d0321d46acfc4 100644 --- a/ecmascript/jspandafile/js_pandafile_manager.h +++ b/ecmascript/jspandafile/js_pandafile_manager.h @@ -19,7 +19,7 @@ #include "ecmascript/mem/c_containers.h" #include "ecmascript/class_linker/panda_file_translator.h" #include "ecmascript/jspandafile/js_pandafile.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/backend/js_pt_extractor.h" #include "libpandafile/file.h" #include "libpandabase/utils/logger.h" @@ -32,8 +32,14 @@ class EcmaVm; namespace ecmascript { class Program; -class JSPandaFileManager { +class PUBLIC_API JSPandaFileManager { public: + static JSPandaFileManager *GetInstance() + { + static JSPandaFileManager jsFileManager; + return &jsFileManager; + } + JSPandaFileManager() = default; ~JSPandaFileManager(); @@ -47,7 +53,7 @@ public: const JSPandaFile *CreateJSPandaFile(const panda_file::File *pf, const CString &desc); - tooling::PtJSExtractor *GetOrCreatePtJSExtractor(const panda_file::File *pf); + tooling::JSPtExtractor *GetJSPtExtractor(const JSPandaFile *pf); static void RemoveJSPandaFile(void *pointer, void *data); diff --git a/ecmascript/class_linker/program_object-inl.h b/ecmascript/jspandafile/program_object-inl.h similarity index 86% rename from ecmascript/class_linker/program_object-inl.h rename to ecmascript/jspandafile/program_object-inl.h index 80a7eada228eb257d95fc09f563cc98beca19ac2..232d2d5e97aaa6b2f3fd025db90a67f8071e0c32 100644 --- a/ecmascript/class_linker/program_object-inl.h +++ b/ecmascript/jspandafile/program_object-inl.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_CLASS_LINKER_PROGRAM_INL_H -#define ECMASCRIPT_CLASS_LINKER_PROGRAM_INL_H +#ifndef ECMASCRIPT_JSPANDAFILE_PROGRAM_INL_H +#define ECMASCRIPT_JSPANDAFILE_PROGRAM_INL_H #include "program_object.h" #include "ecmascript/mem/native_area_allocator.h" @@ -27,4 +27,4 @@ JSTaggedValue ConstantPool::GetObjectFromCache(uint32_t index) const } } // namespace ecmascript } // namespace panda -#endif // ECMASCRIPT_CLASS_LINKER_PROGRAM_INL_H \ No newline at end of file +#endif // ECMASCRIPT_JSPANDAFILE_PROGRAM_INL_H \ No newline at end of file diff --git a/ecmascript/class_linker/program_object.h b/ecmascript/jspandafile/program_object.h similarity index 91% rename from ecmascript/class_linker/program_object.h rename to ecmascript/jspandafile/program_object.h index cdfe17ff663265b192a49fa7ca2b202e0ac4f9f0..cb74072dc549fbf50d293bc2aa0a469dee60f79b 100644 --- a/ecmascript/class_linker/program_object.h +++ b/ecmascript/jspandafile/program_object.h @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_CLASS_LINKER_PROGRAM_H -#define ECMASCRIPT_CLASS_LINKER_PROGRAM_H +#ifndef ECMASCRIPT_JSPANDAFILE_PROGRAM_H +#define ECMASCRIPT_JSPANDAFILE_PROGRAM_H #include "ecmascript/ecma_macros.h" #include "ecmascript/js_tagged_value-inl.h" @@ -48,4 +48,4 @@ public: }; } // namespace ecmascript } // namespace panda -#endif // ECMASCRIPT_CLASS_LINKER_PROGRAM_H +#endif // ECMASCRIPT_JSPANDAFILE_PROGRAM_H diff --git a/ecmascript/scope_info_extractor.cpp b/ecmascript/jspandafile/scope_info_extractor.cpp similarity index 97% rename from ecmascript/scope_info_extractor.cpp rename to ecmascript/jspandafile/scope_info_extractor.cpp index f66a877e981418e86c4e7784422c387a3f8f958f..53eabd99b60ee9e15d369f22ccd77abcad85b8ea 100644 --- a/ecmascript/scope_info_extractor.cpp +++ b/ecmascript/jspandafile/scope_info_extractor.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "ecmascript/scope_info_extractor.h" +#include "ecmascript/jspandafile/scope_info_extractor.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/literal_data_extractor.h" #include "ecmascript/tagged_array-inl.h" diff --git a/ecmascript/scope_info_extractor.h b/ecmascript/jspandafile/scope_info_extractor.h similarity index 100% rename from ecmascript/scope_info_extractor.h rename to ecmascript/jspandafile/scope_info_extractor.h diff --git a/ecmascript/mem/object_xray-inl.h b/ecmascript/mem/object_xray-inl.h index 9e09228b010f5ce53b926a277694a018ec4fba0b..19ae3f5515a0003c69cd7ad5991488b4bd78f26e 100644 --- a/ecmascript/mem/object_xray-inl.h +++ b/ecmascript/mem/object_xray-inl.h @@ -18,7 +18,7 @@ #include #include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" diff --git a/ecmascript/napi/dfx_jsnapi.cpp b/ecmascript/napi/dfx_jsnapi.cpp index 8710375e9dc6d5b0ccc327f55341a2daaf5651c5..75e6033ed242c0f88e67d5b4d0c6cc8e5dc99fec 100644 --- a/ecmascript/napi/dfx_jsnapi.cpp +++ b/ecmascript/napi/dfx_jsnapi.cpp @@ -43,8 +43,7 @@ void DFXJSNApi::DumpHeapSnapShot(EcmaVM *vm, int dumpFormat, const std::string std::string DFXJSNApi::BuildNativeAndJsBackStackTrace(EcmaVM *vm) { - CString trace = ecmascript::base::ErrorHelper::BuildNativeAndJsStackTrace(vm->GetJSThreadNoCheck()); - std::string result = CstringConvertToStdString(trace); + std::string result = ecmascript::base::ErrorHelper::BuildNativeAndJsStackTrace(vm->GetJSThreadNoCheck()); return result; } @@ -93,12 +92,12 @@ size_t DFXJSNApi::GetArrayBufferSize(EcmaVM *vm) return vm->GetHeap()->GetArrayBufferSize(); } -size_t DFXJSNApi::GetHeapTotalSize(EcmaVM *vm) +size_t DFXJSNApi::GetHeapTotalSize(const EcmaVM *vm) { return vm->GetHeap()->GetCommittedSize(); } -size_t DFXJSNApi::GetHeapUsedSize(EcmaVM *vm) +size_t DFXJSNApi::GetHeapUsedSize(const EcmaVM *vm) { return vm->GetHeap()->GetHeapObjectSize(); } diff --git a/ecmascript/napi/include/dfx_jsnapi.h b/ecmascript/napi/include/dfx_jsnapi.h index bc9122066e5a122c01dddffaf5a3b8083712d4f8..7ba5352f34bcb393a4621e95f24755fe36141b53 100644 --- a/ecmascript/napi/include/dfx_jsnapi.h +++ b/ecmascript/napi/include/dfx_jsnapi.h @@ -41,8 +41,8 @@ public: static void StartRuntimeStat(EcmaVM *vm); static void StopRuntimeStat(EcmaVM *vm); static size_t GetArrayBufferSize(EcmaVM *vm); - static size_t GetHeapTotalSize(EcmaVM *vm); - static size_t GetHeapUsedSize(EcmaVM *vm); + static size_t GetHeapTotalSize(const EcmaVM *vm); + static size_t GetHeapUsedSize(const EcmaVM *vm); }; } #endif \ No newline at end of file diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index ac670ff3c0d7e4936ff32a6c4863fc6780e43470..e69658a1e352a79d0469fef1c8bc332f2198c842 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -21,7 +21,7 @@ #include "ecmascript/builtins/builtins_errors.h" #include "ecmascript/builtins/builtins_global.h" #include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/ecma_macros.h" #include "ecmascript/ecma_module.h" #include "ecmascript/free_object.h" @@ -345,11 +345,11 @@ JSHandle ObjectFactory::CloneProperties(const JSHandle return EmptyArray(); } NewObjectHook(); - auto klass = old->GetClass(); - size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength); - auto header = heap_->AllocateYoungOrHugeObject(klass, size); - JSHandle newArray(thread_, header); - newArray->SetLength(newLength); + auto klass = old->GetClass(); + size_t size = TaggedArray::ComputeSize(JSTaggedValue::TaggedTypeSize(), newLength); + auto header = heap_->AllocateYoungOrHugeObject(klass, size); + JSHandle newArray(thread_, header); + newArray->SetLength(newLength); for (uint32_t i = 0; i < newLength; i++) { JSTaggedValue value = old->Get(i); diff --git a/ecmascript/platform/runner.h b/ecmascript/platform/runner.h index 1a9b75ceeb63127e158508d9e12bbe0cf79cf94e..59ad3a737790523221e9e62c72b7e6ff7984095a 100644 --- a/ecmascript/platform/runner.h +++ b/ecmascript/platform/runner.h @@ -20,6 +20,7 @@ #include #include +#include "ecmascript/common.h" #include "ecmascript/platform/task_queue.h" namespace panda::ecmascript { @@ -39,7 +40,7 @@ public: taskQueue_.PostTask(std::move(task)); } - void TerminateThread(); + PUBLIC_API void TerminateThread(); void TerminateTask(); uint32_t GetTotalThreadNum() const diff --git a/ecmascript/snapshot/mem/snapshot.cpp b/ecmascript/snapshot/mem/snapshot.cpp index 83f88306add64d0b3d52fd4a9ea102bed177591c..52622d4070b927006825794f322deac13beb0209 100644 --- a/ecmascript/snapshot/mem/snapshot.cpp +++ b/ecmascript/snapshot/mem/snapshot.cpp @@ -20,7 +20,7 @@ #include #include -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/jobs/micro_job_queue.h" diff --git a/ecmascript/snapshot/mem/snapshot_serialize.cpp b/ecmascript/snapshot/mem/snapshot_serialize.cpp index 67d19721b3bc644042117f19d824c6d98c4837f9..ba3a67ab8219e04a58bf392a8239d44372f2b2bf 100644 --- a/ecmascript/snapshot/mem/snapshot_serialize.cpp +++ b/ecmascript/snapshot/mem/snapshot_serialize.cpp @@ -53,7 +53,7 @@ #include "ecmascript/builtins/builtins_typedarray.h" #include "ecmascript/builtins/builtins_weak_map.h" #include "ecmascript/builtins/builtins_weak_set.h" -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/containers/containers_arraylist.h" #include "ecmascript/containers/containers_treemap.h" #include "ecmascript/containers/containers_treeset.h" diff --git a/ecmascript/tests/dump_test.cpp b/ecmascript/tests/dump_test.cpp index b81a5e943ff600cf5b2700bf2f4109e8261d6a18..5101774a875b07785723e40d2b64a32572689da2 100644 --- a/ecmascript/tests/dump_test.cpp +++ b/ecmascript/tests/dump_test.cpp @@ -15,7 +15,7 @@ #include "ecmascript/accessor_data.h" #include "ecmascript/class_info_extractor.h" -#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/jspandafile/program_object-inl.h" #include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_dictionary-inl.h" diff --git a/ecmascript/tooling/BUILD.gn b/ecmascript/tooling/BUILD.gn index 04e9c294a20feb7de6db3254f3ddcc55d28323ae..bdea7afcc3a484edb0c076869b66b0a017e1b388 100644 --- a/ecmascript/tooling/BUILD.gn +++ b/ecmascript/tooling/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2021 Huawei Device Co., Ltd. +# Copyright (c) 2021-2022 Huawei Device Co., Ltd. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -15,18 +15,29 @@ import("//ark/js_runtime/js_runtime_config.gni") import("//build/ohos.gni") config("ark_ecma_debugger_config") { + configs = [ + "//ark/js_runtime:ark_jsruntime_common_config", + "//ark/js_runtime:ark_jsruntime_public_config", + "$ark_root/runtime:arkruntime_public_config", + ] + include_dirs = [ - "//ark/js_runtime/ecmascript/tooling", + ".", "//third_party/boost", + "//third_party/cJSON", ] } debugger_sources = [ "agent/debugger_impl.cpp", - "agent/js_backend.cpp", - "agent/js_pt_hooks.cpp", + # "agent/heapprofiler_impl.cpp", + # "agent/profiler_impl.cpp", "agent/runtime_impl.cpp", + "backend/debugger_executor.cpp", + "backend/js_pt_extractor.cpp", + "backend/js_pt_hooks.cpp", "base/pt_events.cpp", + "base/pt_json.cpp", "base/pt_params.cpp", "base/pt_returns.cpp", "base/pt_script.cpp", @@ -34,23 +45,17 @@ debugger_sources = [ "debugger_service.cpp", "dispatcher.cpp", "protocol_handler.cpp", - "pt_js_extractor.cpp", ] -source_set("libark_ecma_debugger_static") { +source_set("libark_ecma_debugger_set") { sources = debugger_sources - public_configs = [ - ":ark_ecma_debugger_config", - "//ark/js_runtime:ark_jsruntime_common_config", - "//ark/js_runtime:ark_jsruntime_public_config", - "$ark_root/runtime:arkruntime_public_config", - ] + public_configs = [ ":ark_ecma_debugger_config" ] deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", - "$ark_root/runtime:arkruntime_header_deps", + "//third_party/cJSON:cjson_static", ] cflags_cc = [ "-fvisibility=hidden" ] @@ -58,48 +63,47 @@ source_set("libark_ecma_debugger_static") { ohos_shared_library("libark_ecma_debugger") { deps = [ - ":libark_ecma_debugger_static", + ":libark_ecma_debugger_set", "//ark/js_runtime:libark_jsruntime", ] - if (!is_standard_system) { - deps += [ "$ark_root/runtime:libarkruntime" ] - } - install_enable = true - part_name = "ark_js_runtime" output_extension = "so" if (!is_standard_system) { relative_install_dir = "ark" } + part_name = "ark_js_runtime" subsystem_name = "ark" } -source_set("libark_ecma_debugger_test_static") { +source_set("libark_ecma_debugger_test_set") { sources = debugger_sources - public_configs = [ - ":ark_ecma_debugger_config", - "//ark/js_runtime:ark_jsruntime_common_config", - "//ark/js_runtime:ark_jsruntime_public_config", - "$ark_root/runtime:arkruntime_public_config", - ] + public_configs = [ ":ark_ecma_debugger_config" ] + + defines = [ "DEBUGGER_TEST" ] deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", - "$ark_root/runtime:arkruntime_header_deps", + "//third_party/cJSON:cjson_static", ] } ohos_shared_library("libark_ecma_debugger_test") { deps = [ - ":libark_ecma_debugger_test_static", - "//ark/js_runtime:libark_jsruntime_test_static", + ":libark_ecma_debugger_test_set", + "//ark/js_runtime:libark_jsruntime_test_set", ] - if (!is_linux) { + if (is_standard_system) { + deps += [ "$ark_root/runtime:libarkruntime_static" ] + } else { + deps += [ "$ark_root/runtime:libarkruntime" ] + } + + if (is_ohos && is_standard_system) { if (build_public_version) { external_deps = [ "bytrace_standard:bytrace_core", @@ -108,18 +112,9 @@ ohos_shared_library("libark_ecma_debugger_test") { } } - configs = [ - ":ark_ecma_debugger_config", - "//ark/js_runtime:ark_jsruntime_common_config", - "//ark/js_runtime:ark_jsruntime_public_config", - "$ark_root/runtime:arkruntime_public_config", - ] + public_configs = [ ":ark_ecma_debugger_config" ] - if (is_standard_system) { - deps += [ "$ark_root/runtime:libarkruntime_static" ] - } else { - deps += [ "$ark_root/runtime:libarkruntime" ] - } + install_enable = false output_extension = "so" subsystem_name = "test" diff --git a/ecmascript/tooling/agent/debugger_impl.cpp b/ecmascript/tooling/agent/debugger_impl.cpp index cf1661c3d68c295eb109f1dad94a5344b71d14c6..6ab89c8456d4f848c554d1a4ff15e98bea2011fb 100644 --- a/ecmascript/tooling/agent/debugger_impl.cpp +++ b/ecmascript/tooling/agent/debugger_impl.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -15,314 +15,1103 @@ #include "ecmascript/tooling/agent/debugger_impl.h" +#include + +#include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/napi/jsnapi_helper-inl.h" #include "ecmascript/tooling/base/pt_events.h" #include "ecmascript/tooling/base/pt_params.h" #include "ecmascript/tooling/base/pt_returns.h" +#include "ecmascript/tooling/base/pt_types.h" +#include "ecmascript/tooling/backend/debugger_executor.h" #include "ecmascript/tooling/dispatcher.h" -#include "ecmascript/tooling/front_end.h" +#include "ecmascript/tooling/protocol_channel.h" #include "libpandabase/utils/logger.h" namespace panda::ecmascript::tooling { -DebuggerImpl::DispatcherImpl::DispatcherImpl(FrontEnd *frontend, std::unique_ptr debugger) - : DispatcherBase(frontend), debugger_(std::move(debugger)) -{ - dispatcherTable_["enable"] = &DebuggerImpl::DispatcherImpl::Enable; - dispatcherTable_["evaluateOnCallFrame"] = &DebuggerImpl::DispatcherImpl::EvaluateOnCallFrame; - dispatcherTable_["getPossibleBreakpoints"] = &DebuggerImpl::DispatcherImpl::GetPossibleBreakpoints; - dispatcherTable_["getScriptSource"] = &DebuggerImpl::DispatcherImpl::GetScriptSource; - dispatcherTable_["pause"] = &DebuggerImpl::DispatcherImpl::Pause; - dispatcherTable_["removeBreakpoint"] = &DebuggerImpl::DispatcherImpl::RemoveBreakpoint; - dispatcherTable_["resume"] = &DebuggerImpl::DispatcherImpl::Resume; - dispatcherTable_["setAsyncCallStackDepth"] = &DebuggerImpl::DispatcherImpl::SetAsyncCallStackDepth; - dispatcherTable_["setBreakpointByUrl"] = &DebuggerImpl::DispatcherImpl::SetBreakpointByUrl; - dispatcherTable_["setPauseOnExceptions"] = &DebuggerImpl::DispatcherImpl::SetPauseOnExceptions; - dispatcherTable_["stepInto"] = &DebuggerImpl::DispatcherImpl::StepInto; - dispatcherTable_["stepOut"] = &DebuggerImpl::DispatcherImpl::StepOut; - dispatcherTable_["stepOver"] = &DebuggerImpl::DispatcherImpl::StepOver; - dispatcherTable_["setBlackboxPatterns"] = &DebuggerImpl::DispatcherImpl::SetBlackboxPatterns; +using namespace boost::beast::detail; +using namespace std::placeholders; + +using ObjectType = RemoteObject::TypeName; +using ObjectSubType = RemoteObject::SubTypeName; +using ObjectClassName = RemoteObject::ClassName; + +#ifdef DEBUGGER_TEST +const std::string DATA_APP_PATH = "/"; +#else +const std::string DATA_APP_PATH = "/data/"; +#endif + +DebuggerImpl::DebuggerImpl(const EcmaVM *vm, ProtocolChannel *channel, RuntimeImpl *runtime) + : vm_(vm), frontend_(channel), runtime_(runtime) +{ + hooks_ = std::make_unique(this); + + jsDebugger_ = DebuggerApi::CreateJSDebugger(vm_); + DebuggerApi::RegisterHooks(jsDebugger_, hooks_.get()); + + DebuggerExecutor::Initialize(vm_); + updaterFunc_ = std::bind(&DebuggerImpl::UpdateScopeObject, this, _1, _2, _3); + vm_->GetJsDebuggerManager()->SetLocalScopeUpdater(&updaterFunc_); +} + +DebuggerImpl::~DebuggerImpl() +{ + DebuggerApi::DestroyJSDebugger(jsDebugger_); +} + +bool DebuggerImpl::NotifyScriptParsed(ScriptId scriptId, const std::string &fileName) +{ + if (fileName.substr(0, DATA_APP_PATH.length()) != DATA_APP_PATH) { + LOG(WARNING, DEBUGGER) << "NotifyScriptParsed: unsupport file: " << fileName; + return false; + } + + auto scriptFunc = []([[maybe_unused]] PtScript *script) -> bool { + return true; + }; + if (MatchScripts(scriptFunc, fileName, ScriptMatchType::FILE_NAME)) { + LOG(WARNING, DEBUGGER) << "NotifyScriptParsed: already loaded: " << fileName; + return false; + } + const JSPandaFile *jsPandaFile = nullptr; + JSPandaFileManager::GetInstance()->EnumerateJSPandaFiles([&jsPandaFile, &fileName]( + const panda::ecmascript::JSPandaFile *pf) { + if (fileName == pf->GetJSPandaFileDesc().c_str()) { + jsPandaFile = pf; + return false; + } + return true; + }); + if (jsPandaFile == nullptr) { + LOG(ERROR, DEBUGGER) << "NotifyScriptParsed: unknown file: " << fileName; + return false; + } + + JSPtExtractor *extractor = GetExtractor(jsPandaFile); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "NotifyScriptParsed: Unsupported file: " << fileName; + return false; + } + + auto mainMethodIndex = panda_file::File::EntityId(jsPandaFile->GetMainMethodIndex()); + const std::string &source = extractor->GetSourceCode(mainMethodIndex); + const std::string &url = extractor->GetSourceFile(mainMethodIndex); + const uint32_t MIN_SOURCE_CODE_LENGTH = 5; // maybe return 'ANDA' when source code is empty + if (source.size() < MIN_SOURCE_CODE_LENGTH) { + LOG(ERROR, DEBUGGER) << "NotifyScriptParsed: invalid file: " << fileName; + return false; + } + // store here for performance of get extractor from url + extractors_[url] = extractor; + + // Notify script parsed event + std::unique_ptr script = std::make_unique(scriptId, fileName, url, source); + + frontend_.ScriptParsed(vm_, *script); + + // Store parsed script in map + scripts_[script->GetScriptId()] = std::move(script); + return true; +} + +bool DebuggerImpl::NotifySingleStep(const JSPtLocation &location) +{ + if (UNLIKELY(pauseOnNextByteCode_)) { + if (IsSkipLine(location)) { + return false; + } + pauseOnNextByteCode_ = false; + LOG(INFO, DEBUGGER) << "StepComplete: pause on next bytecode"; + return true; + } + + if (LIKELY(singleStepper_ == nullptr)) { + return false; + } + + // step not complete + if (!singleStepper_->StepComplete(location.GetBytecodeOffset())) { + return false; + } + + // skip unknown file or special line -1 + if (IsSkipLine(location)) { + return false; + } + + LOG(INFO, DEBUGGER) << "StepComplete: pause on current byte_code"; + return true; +} + +bool DebuggerImpl::IsSkipLine(const JSPtLocation &location) +{ + JSPtExtractor *extractor = nullptr; + auto scriptFunc = [this, &extractor](PtScript *script) -> bool { + extractor = GetExtractor(script->GetUrl()); + return true; + }; + if (!MatchScripts(scriptFunc, location.GetPandaFile(), ScriptMatchType::FILE_NAME) || extractor == nullptr) { + LOG(INFO, DEBUGGER) << "StepComplete: skip unknown file"; + return true; + } + + auto callbackFunc = [](int32_t line) -> bool { + return line == JSPtExtractor::SPECIAL_LINE_MARK; + }; + File::EntityId methodId = location.GetMethodId(); + uint32_t offset = location.GetBytecodeOffset(); + if (extractor->MatchLineWithOffset(callbackFunc, methodId, offset)) { + LOG(INFO, DEBUGGER) << "StepComplete: skip -1"; + return true; + } + + return false; +} + +void DebuggerImpl::NotifyPaused(std::optional location, PauseReason reason) +{ + if (!pauseOnException_ && reason == EXCEPTION) { + return; + } + Local exception = DebuggerApi::GetAndClearException(vm_); + + std::vector hitBreakpoints; + if (location.has_value()) { + BreakpointDetails detail; + JSPtExtractor *extractor = nullptr; + auto scriptFunc = [this, &extractor, &detail](PtScript *script) -> bool { + detail.url_ = script->GetUrl(); + extractor = GetExtractor(detail.url_); + return true; + }; + auto callbackLineFunc = [&detail](int32_t line) -> bool { + detail.line_ = line; + return true; + }; + auto callbackColumnFunc = [&detail](int32_t column) -> bool { + detail.column_ = column; + return true; + }; + File::EntityId methodId = location->GetMethodId(); + uint32_t offset = location->GetBytecodeOffset(); + if (!MatchScripts(scriptFunc, location->GetPandaFile(), ScriptMatchType::FILE_NAME) || + extractor == nullptr || !extractor->MatchLineWithOffset(callbackLineFunc, methodId, offset) || + !extractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset)) { + LOG(ERROR, DEBUGGER) << "NotifyPaused: unknown " << location->GetPandaFile(); + return; + } + hitBreakpoints.emplace_back(BreakpointDetails::ToString(detail)); + } + + // Do something cleaning on paused + CleanUpOnPaused(); + + // Notify paused event + std::vector> callFrames; + if (!GenerateCallFrames(&callFrames)) { + LOG(ERROR, DEBUGGER) << "NotifyPaused: GenerateCallFrames failed"; + return; + } + tooling::Paused paused; + paused.SetCallFrames(std::move(callFrames)).SetReason(reason).SetHitBreakpoints(std::move(hitBreakpoints)); + if (reason == EXCEPTION && exception->IsError()) { + std::unique_ptr tmpException = RemoteObject::FromTagged(vm_, exception); + paused.SetData(std::move(tmpException)); + } + frontend_.Paused(vm_, paused); + + // Waiting for Debugger + frontend_.WaitForDebugger(vm_); + DebuggerApi::SetException(vm_, exception); +} + +void DebuggerImpl::NotifyPendingJobEntry() +{ + if (singleStepper_ != nullptr) { + singleStepper_.reset(); + pauseOnNextByteCode_ = true; + } } void DebuggerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request) { - CString method = request.GetMethod(); + static std::unordered_map dispatcherTable { + { "enable", &DebuggerImpl::DispatcherImpl::Enable }, + { "disable", &DebuggerImpl::DispatcherImpl::Disable }, + { "evaluateOnCallFrame", &DebuggerImpl::DispatcherImpl::EvaluateOnCallFrame }, + { "getPossibleBreakpoints", &DebuggerImpl::DispatcherImpl::GetPossibleBreakpoints }, + { "getScriptSource", &DebuggerImpl::DispatcherImpl::GetScriptSource }, + { "pause", &DebuggerImpl::DispatcherImpl::Pause }, + { "removeBreakpoint", &DebuggerImpl::DispatcherImpl::RemoveBreakpoint }, + { "resume", &DebuggerImpl::DispatcherImpl::Resume }, + { "setAsyncCallStackDepth", &DebuggerImpl::DispatcherImpl::SetAsyncCallStackDepth }, + { "setBreakpointByUrl", &DebuggerImpl::DispatcherImpl::SetBreakpointByUrl }, + { "setPauseOnExceptions", &DebuggerImpl::DispatcherImpl::SetPauseOnExceptions }, + { "stepInto", &DebuggerImpl::DispatcherImpl::StepInto }, + { "stepOut", &DebuggerImpl::DispatcherImpl::StepOut }, + { "stepOver", &DebuggerImpl::DispatcherImpl::StepOver } + }; + + const std::string &method = request.GetMethod(); LOG(DEBUG, DEBUGGER) << "dispatch [" << method << "] to DebuggerImpl"; - auto entry = dispatcherTable_.find(method); - if (entry != dispatcherTable_.end() && entry->second != nullptr) { + auto entry = dispatcherTable.find(method); + if (entry != dispatcherTable.end() && entry->second != nullptr) { (this->*(entry->second))(request); } else { - SendResponse(request, DispatchResponse::Fail("Unknown method: " + method), nullptr); + SendResponse(request, DispatchResponse::Fail("Unknown method: " + method)); } } void DebuggerImpl::DispatcherImpl::Enable(const DispatchRequest &request) { - std::unique_ptr params = EnableParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = EnableParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } UniqueDebuggerId id; - DispatchResponse response = debugger_->Enable(std::move(params), &id); + DispatchResponse response = debugger_->Enable(*params, &id); + + EnableReturns result(id); + SendResponse(request, response, result); +} - std::unique_ptr result = std::make_unique(id); - SendResponse(request, response, std::move(result)); +void DebuggerImpl::DispatcherImpl::Disable(const DispatchRequest &request) +{ + DispatchResponse response = debugger_->Disable(); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::EvaluateOnCallFrame(const DispatchRequest &request) { - std::unique_ptr params = - EvaluateOnCallFrameParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = EvaluateOnCallFrameParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - std::unique_ptr result1 = std::make_unique(); - DispatchResponse response = debugger_->EvaluateOnCallFrame(std::move(params), &result1); + std::unique_ptr result1; + DispatchResponse response = debugger_->EvaluateOnCallFrame(*params, &result1); - std::unique_ptr result = - std::make_unique(std::move(result1)); - SendResponse(request, response, std::move(result)); + EvaluateOnCallFrameReturns result(std::move(result1)); + SendResponse(request, response, result); } void DebuggerImpl::DispatcherImpl::GetPossibleBreakpoints(const DispatchRequest &request) { - std::unique_ptr params = - GetPossibleBreakpointsParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = GetPossibleBreakpointsParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - CVector> locations; - DispatchResponse response = debugger_->GetPossibleBreakpoints(std::move(params), &locations); - std::unique_ptr points = - std::make_unique(std::move(locations)); - SendResponse(request, response, std::move(points)); + std::vector> locations; + DispatchResponse response = debugger_->GetPossibleBreakpoints(*params, &locations); + GetPossibleBreakpointsReturns result(std::move(locations)); + SendResponse(request, response, result); } void DebuggerImpl::DispatcherImpl::GetScriptSource(const DispatchRequest &request) { - std::unique_ptr params = - GetScriptSourceParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = GetScriptSourceParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - CString source; - DispatchResponse response = debugger_->GetScriptSource(std::move(params), &source); - std::unique_ptr result = std::make_unique(std::move(source)); - SendResponse(request, response, std::move(result)); + std::string source; + DispatchResponse response = debugger_->GetScriptSource(*params, &source); + GetScriptSourceReturns result(source); + SendResponse(request, response, result); } void DebuggerImpl::DispatcherImpl::Pause(const DispatchRequest &request) { DispatchResponse response = debugger_->Pause(); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::RemoveBreakpoint(const DispatchRequest &request) { - std::unique_ptr params = - RemoveBreakpointParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = RemoveBreakpointParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - DispatchResponse response = debugger_->RemoveBreakpoint(std::move(params)); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + DispatchResponse response = debugger_->RemoveBreakpoint(*params); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::Resume(const DispatchRequest &request) { - std::unique_ptr params = ResumeParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = ResumeParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - DispatchResponse response = debugger_->Resume(std::move(params)); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + DispatchResponse response = debugger_->Resume(*params); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::SetAsyncCallStackDepth(const DispatchRequest &request) { DispatchResponse response = debugger_->SetAsyncCallStackDepth(); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::SetBreakpointByUrl(const DispatchRequest &request) { - std::unique_ptr params = - SetBreakpointByUrlParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = SetBreakpointByUrlParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - CString out_id; - CVector> outLocations; - DispatchResponse response = debugger_->SetBreakpointByUrl(std::move(params), &out_id, &outLocations); - std::unique_ptr result = - std::make_unique(out_id, std::move(outLocations)); - SendResponse(request, response, std::move(result)); + std::string out_id; + std::vector> outLocations; + DispatchResponse response = debugger_->SetBreakpointByUrl(*params, &out_id, &outLocations); + SetBreakpointByUrlReturns result(out_id, std::move(outLocations)); + SendResponse(request, response, result); } void DebuggerImpl::DispatcherImpl::SetPauseOnExceptions(const DispatchRequest &request) { - std::unique_ptr params = - SetPauseOnExceptionsParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = SetPauseOnExceptionsParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - DispatchResponse response = debugger_->SetPauseOnExceptions(std::move(params)); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + DispatchResponse response = debugger_->SetPauseOnExceptions(*params); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::StepInto(const DispatchRequest &request) { - std::unique_ptr params = StepIntoParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = StepIntoParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - DispatchResponse response = debugger_->StepInto(std::move(params)); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + DispatchResponse response = debugger_->StepInto(*params); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::StepOut(const DispatchRequest &request) { DispatchResponse response = debugger_->StepOut(); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::StepOver(const DispatchRequest &request) { - std::unique_ptr params = StepOverParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = StepOverParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - DispatchResponse response = debugger_->StepOver(std::move(params)); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + DispatchResponse response = debugger_->StepOver(*params); + SendResponse(request, response); } void DebuggerImpl::DispatcherImpl::SetBlackboxPatterns(const DispatchRequest &request) { DispatchResponse response = debugger_->SetBlackboxPatterns(); - std::unique_ptr result = std::make_unique(); - SendResponse(request, response, std::move(result)); + SendResponse(request, response); +} + +bool DebuggerImpl::Frontend::AllowNotify(const EcmaVM *vm) const +{ + return vm->GetJsDebuggerManager()->IsDebugMode() && channel_ != nullptr; +} + +void DebuggerImpl::Frontend::BreakpointResolved(const EcmaVM *vm) +{ + if (!AllowNotify(vm)) { + return; + } + + tooling::BreakpointResolved breakpointResolved; + channel_->SendNotification(breakpointResolved); +} + +void DebuggerImpl::Frontend::Paused(const EcmaVM *vm, const tooling::Paused &paused) +{ + if (!AllowNotify(vm)) { + return; + } + + channel_->SendNotification(paused); +} + +void DebuggerImpl::Frontend::Resumed(const EcmaVM *vm) +{ + if (!AllowNotify(vm)) { + return; + } + + channel_->RunIfWaitingForDebugger(); + tooling::Resumed resumed; + channel_->SendNotification(resumed); +} + +void DebuggerImpl::Frontend::ScriptFailedToParse(const EcmaVM *vm) +{ + if (!AllowNotify(vm)) { + return; + } + + tooling::ScriptFailedToParse scriptFailedToParse; + channel_->SendNotification(scriptFailedToParse); +} + +void DebuggerImpl::Frontend::ScriptParsed(const EcmaVM *vm, const PtScript &script) +{ + if (!AllowNotify(vm)) { + return; + } + + tooling::ScriptParsed scriptParsed; + scriptParsed.SetScriptId(script.GetScriptId()) + .SetUrl(script.GetUrl()) + .SetStartLine(0) + .SetStartColumn(0) + .SetEndLine(script.GetEndLine()) + .SetEndColumn(0) + .SetExecutionContextId(0) + .SetHash(script.GetHash()); + + channel_->SendNotification(scriptParsed); +} + +void DebuggerImpl::Frontend::WaitForDebugger(const EcmaVM *vm) +{ + if (!AllowNotify(vm)) { + return; + } + + channel_->WaitForDebugger(); } -DispatchResponse DebuggerImpl::Enable([[maybe_unused]] std::unique_ptr params, UniqueDebuggerId *id) +DispatchResponse DebuggerImpl::Enable([[maybe_unused]] const EnableParams ¶ms, UniqueDebuggerId *id) { ASSERT(id != nullptr); - *id = "0"; + *id = 0; + vm_->GetJsDebuggerManager()->SetDebugMode(true); + for (auto &script : scripts_) { + frontend_.ScriptParsed(vm_, *script.second); + } return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::EvaluateOnCallFrame(std::unique_ptr params, - std::unique_ptr *result) +DispatchResponse DebuggerImpl::Disable() { - CString callFrameId = params->GetCallFrameId(); - CString expression = params->GetExpression(); - return DispatchResponse::Create(backend_->EvaluateValue(callFrameId, expression, result)); + vm_->GetJsDebuggerManager()->SetDebugMode(false); + return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::GetPossibleBreakpoints(std::unique_ptr params, - CVector> *locations) +DispatchResponse DebuggerImpl::EvaluateOnCallFrame(const EvaluateOnCallFrameParams ¶ms, + std::unique_ptr *result) { - Location *locationStart = params->GetStart(); - Location *locationEnd = params->GetEnd(); + CallFrameId callFrameId = params.GetCallFrameId(); + const std::string &expression = params.GetExpression(); + if (callFrameId < 0 || callFrameId >= static_cast(callFrameHandlers_.size())) { + return DispatchResponse::Fail("Invalid callFrameId."); + } + + std::string dest; + if (!DecodeAndCheckBase64(expression, dest)) { + LOG(ERROR, DEBUGGER) << "EvaluateValue: base64 decode failed"; + auto ret = CmptEvaluateValue(callFrameId, expression, result); + if (ret.has_value()) { + LOG(ERROR, DEBUGGER) << "Evaluate fail, expression: " << expression; + } + return DispatchResponse::Create(ret); + } + + auto funcRef = DebuggerApi::GenerateFuncFromBuffer(vm_, dest.data(), dest.size()); + auto res = DebuggerApi::EvaluateViaFuncCall(const_cast(vm_), funcRef, + callFrameHandlers_[callFrameId]); + if (vm_->GetJSThread()->HasPendingException()) { + LOG(ERROR, DEBUGGER) << "EvaluateValue: has pending exception"; + std::string msg; + DebuggerApi::HandleUncaughtException(vm_, msg); + *result = RemoteObject::FromTagged(vm_, + Exception::EvalError(vm_, StringRef::NewFromUtf8(vm_, msg.data()))); + return DispatchResponse::Fail(msg); + } - return DispatchResponse::Create(backend_->GetPossibleBreakpoints(locationStart, locationEnd, locations)); + *result = RemoteObject::FromTagged(vm_, res); + runtime_->CacheObjectIfNeeded(res, (*result).get()); + return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::GetScriptSource(std::unique_ptr params, CString *source) +DispatchResponse DebuggerImpl::GetPossibleBreakpoints(const GetPossibleBreakpointsParams ¶ms, + std::vector> *locations) { - auto scriptFunc = [source](PtScript *script) -> bool { - *source = script->GetScriptSource(); + Location *start = params.GetStart(); + auto iter = scripts_.find(start->GetScriptId()); + if (iter == scripts_.end()) { + return DispatchResponse::Fail("Unknown file name."); + } + JSPtExtractor *extractor = GetExtractor(iter->second->GetUrl()); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "GetPossibleBreakpoints: extractor is null"; + return DispatchResponse::Fail("Unknown file name."); + } + + int32_t line = start->GetLine(); + int32_t column = start->GetColumn(); + auto callbackFunc = []([[maybe_unused]] File::EntityId id, [[maybe_unused]] uint32_t offset) -> bool { return true; }; - if (!backend_->MatchScripts(scriptFunc, params->GetScriptId(), ScriptMatchType::SCRIPT_ID)) { + if (extractor->MatchWithLocation(callbackFunc, line, column)) { + std::unique_ptr location = std::make_unique(); + location->SetScriptId(start->GetScriptId()).SetLine(line).SetColumn(column); + locations->emplace_back(std::move(location)); + } + return DispatchResponse::Ok(); +} + +DispatchResponse DebuggerImpl::GetScriptSource(const GetScriptSourceParams ¶ms, std::string *source) +{ + ScriptId scriptId = params.GetScriptId(); + auto iter = scripts_.find(scriptId); + if (iter == scripts_.end()) { *source = ""; - return DispatchResponse::Fail("unknown script id: " + params->GetScriptId()); + return DispatchResponse::Fail("unknown script id: " + std::to_string(scriptId)); } + *source = iter->second->GetScriptSource(); return DispatchResponse::Ok(); } DispatchResponse DebuggerImpl::Pause() { - return DispatchResponse::Create(backend_->Pause()); + pauseOnNextByteCode_ = true; + return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::RemoveBreakpoint(std::unique_ptr params) +DispatchResponse DebuggerImpl::RemoveBreakpoint(const RemoveBreakpointParams ¶ms) { - CString id = params->GetBreakpointId(); + std::string id = params.GetBreakpointId(); LOG(INFO, DEBUGGER) << "RemoveBreakpoint: " << id; BreakpointDetails metaData{}; if (!BreakpointDetails::ParseBreakpointId(id, &metaData)) { return DispatchResponse::Fail("Parse breakpoint id failed"); } - return DispatchResponse::Create(backend_->RemoveBreakpoint(metaData)); + JSPtExtractor *extractor = GetExtractor(metaData.url_); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "RemoveBreakpoint: extractor is null"; + return DispatchResponse::Fail("Unknown file name."); + } + + std::string fileName; + auto scriptFunc = [&fileName](PtScript *script) -> bool { + fileName = script->GetFileName(); + return true; + }; + if (!MatchScripts(scriptFunc, metaData.url_, ScriptMatchType::URL)) { + LOG(ERROR, DEBUGGER) << "RemoveBreakpoint: Unknown url: " << metaData.url_; + return DispatchResponse::Fail("Unknown file name."); + } + + auto callbackFunc = [this, fileName](File::EntityId id, uint32_t offset) -> bool { + JSPtLocation location {fileName.c_str(), id, offset}; + return DebuggerApi::RemoveBreakpoint(jsDebugger_, location); + }; + if (!extractor->MatchWithLocation(callbackFunc, metaData.line_, metaData.column_)) { + LOG(ERROR, DEBUGGER) << "failed to set breakpoint location number: " + << metaData.line_ << ":" << metaData.column_; + return DispatchResponse::Fail("Breakpoint not found."); + } + + LOG(INFO, DEBUGGER) << "remove breakpoint32_t line number:" << metaData.line_; + return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::Resume([[maybe_unused]] std::unique_ptr params) +DispatchResponse DebuggerImpl::Resume([[maybe_unused]] const ResumeParams ¶ms) { - return DispatchResponse::Create(backend_->Resume()); + frontend_.Resumed(vm_); + singleStepper_.reset(); + return DispatchResponse::Ok(); } DispatchResponse DebuggerImpl::SetAsyncCallStackDepth() { + LOG(ERROR, DEBUGGER) << "SetAsyncCallStackDepth not support now."; return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::SetBreakpointByUrl(std::unique_ptr params, - CString *outId, - CVector> *outLocations) +DispatchResponse DebuggerImpl::SetBreakpointByUrl(const SetBreakpointByUrlParams ¶ms, + std::string *outId, + std::vector> *outLocations) { - return DispatchResponse::Create( - backend_->SetBreakpointByUrl(params->GetUrl(), params->GetLine(), params->GetColumn(), - (params->HasCondition() ? params->GetCondition() : std::optional {}), outId, outLocations)); + const std::string &url = params.GetUrl(); + int32_t lineNumber = params.GetLine(); + int32_t columnNumber = params.GetColumn(); + auto condition = params.HasCondition() ? params.GetCondition() : std::optional {}; + + JSPtExtractor *extractor = GetExtractor(url); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: extractor is null"; + return DispatchResponse::Fail("Unknown file name."); + } + + ScriptId scriptId; + std::string fileName; + auto scriptFunc = [&scriptId, &fileName](PtScript *script) -> bool { + scriptId = script->GetScriptId(); + fileName = script->GetFileName(); + return true; + }; + if (!MatchScripts(scriptFunc, url, ScriptMatchType::URL)) { + LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: Unknown url: " << url; + return DispatchResponse::Fail("Unknown file name."); + } + + auto callbackFunc = [this, fileName, &condition](File::EntityId id, uint32_t offset) -> bool { + JSPtLocation location {fileName.c_str(), id, offset}; + Local condFuncRef = FunctionRef::Undefined(vm_); + if (condition.has_value() && !condition.value().empty()) { + std::string dest; + if (!DecodeAndCheckBase64(condition.value(), dest)) { + LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: base64 decode failed"; + return false; + } + condFuncRef = DebuggerApi::GenerateFuncFromBuffer(vm_, dest.data(), dest.size()); + if (condFuncRef->IsUndefined()) { + LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: generate function failed"; + return false; + } + } + return DebuggerApi::SetBreakpoint(jsDebugger_, location, condFuncRef); + }; + if (!extractor->MatchWithLocation(callbackFunc, lineNumber, columnNumber)) { + LOG(ERROR, DEBUGGER) << "failed to set breakpoint location number: " << lineNumber << ":" << columnNumber; + return DispatchResponse::Fail("Breakpoint not found."); + } + + BreakpointDetails metaData{lineNumber, 0, url}; + *outId = BreakpointDetails::ToString(metaData); + *outLocations = std::vector>(); + std::unique_ptr location = std::make_unique(); + location->SetScriptId(scriptId).SetLine(lineNumber).SetColumn(0); + outLocations->emplace_back(std::move(location)); + + return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::SetPauseOnExceptions(std::unique_ptr params) +DispatchResponse DebuggerImpl::SetPauseOnExceptions(const SetPauseOnExceptionsParams ¶ms) { - PauseOnExceptionsState state = params->GetState(); - if (state == PauseOnExceptionsState::UNCAUGHT) { - backend_->SetPauseOnException(false); - } else { - backend_->SetPauseOnException(true); - } + PauseOnExceptionsState state = params.GetState(); + pauseOnException_ = (state != PauseOnExceptionsState::UNCAUGHT); + return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::StepInto([[maybe_unused]] std::unique_ptr params) +DispatchResponse DebuggerImpl::StepInto([[maybe_unused]] const StepIntoParams ¶ms) { - return DispatchResponse::Create(backend_->StepInto()); + JSMethod *method = DebuggerApi::GetMethod(vm_); + JSPtExtractor *extractor = GetExtractor(method->GetJSPandaFile()); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "StepOver: extractor is null"; + return DispatchResponse::Fail("Unknown file name."); + } + singleStepper_ = extractor->GetStepIntoStepper(vm_); + + frontend_.Resumed(vm_); + return DispatchResponse::Ok(); } DispatchResponse DebuggerImpl::StepOut() { - return DispatchResponse::Create(backend_->StepOut()); + JSMethod *method = DebuggerApi::GetMethod(vm_); + JSPtExtractor *extractor = GetExtractor(method->GetJSPandaFile()); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "StepOut: extractor is null"; + return DispatchResponse::Fail("Unknown file name."); + } + singleStepper_ = extractor->GetStepOutStepper(vm_); + + frontend_.Resumed(vm_); + return DispatchResponse::Ok(); } -DispatchResponse DebuggerImpl::StepOver([[maybe_unused]] std::unique_ptr params) +DispatchResponse DebuggerImpl::StepOver([[maybe_unused]] const StepOverParams ¶ms) { - return DispatchResponse::Create(backend_->StepOver()); + JSMethod *method = DebuggerApi::GetMethod(vm_); + JSPtExtractor *extractor = GetExtractor(method->GetJSPandaFile()); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "StepOver: extractor is null"; + return DispatchResponse::Fail("Unknown file name."); + } + singleStepper_ = extractor->GetStepOverStepper(vm_); + + frontend_.Resumed(vm_); + return DispatchResponse::Ok(); } DispatchResponse DebuggerImpl::SetBlackboxPatterns() { + LOG(ERROR, DEBUGGER) << "SetBlackboxPatterns not support now."; return DispatchResponse::Ok(); } + +void DebuggerImpl::CleanUpOnPaused() +{ + runtime_->curObjectId_ = 0; + runtime_->properties_.clear(); + + callFrameHandlers_.clear(); + scopeObjects_.clear(); +} + +std::string DebuggerImpl::Trim(const std::string &str) +{ + std::string ret = str; + // If ret has only ' ', remove all charactors. + ret.erase(ret.find_last_not_of(' ') + 1); + // If ret has only ' ', remove all charactors. + ret.erase(0, ret.find_first_not_of(' ')); + return ret; +} + +JSPtExtractor *DebuggerImpl::GetExtractor(const JSPandaFile *jsPandaFile) +{ + return JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile); +} + +JSPtExtractor *DebuggerImpl::GetExtractor(const std::string &url) +{ + auto iter = extractors_.find(url); + if (iter == extractors_.end()) { + return nullptr; + } + + return iter->second; +} + +bool DebuggerImpl::GenerateCallFrames(std::vector> *callFrames) +{ + CallFrameId callFrameId = 0; + auto walkerFunc = [this, &callFrameId, &callFrames](const InterpretedFrameHandler *frameHandler) -> StackState { + JSMethod *method = DebuggerApi::GetMethod(frameHandler); + if (method->IsNativeWithCallField()) { + LOG(INFO, DEBUGGER) << "GenerateCallFrames: Skip CFrame and Native method"; + return StackState::CONTINUE; + } + std::unique_ptr callFrame = std::make_unique(); + if (!GenerateCallFrame(callFrame.get(), frameHandler, callFrameId)) { + if (callFrameId == 0) { + return StackState::FAILED; + } + } else { + SaveCallFrameHandler(frameHandler); + callFrames->emplace_back(std::move(callFrame)); + callFrameId++; + } + return StackState::CONTINUE; + }; + return DebuggerApi::StackWalker(vm_, walkerFunc); +} + +void DebuggerImpl::SaveCallFrameHandler(const InterpretedFrameHandler *frameHandler) +{ + auto handlerPtr = DebuggerApi::NewFrameHandler(vm_); + *handlerPtr = *frameHandler; + callFrameHandlers_.emplace_back(handlerPtr); +} + +bool DebuggerImpl::GenerateCallFrame(CallFrame *callFrame, + const InterpretedFrameHandler *frameHandler, CallFrameId callFrameId) +{ + JSMethod *method = DebuggerApi::GetMethod(frameHandler); + JSPtExtractor *extractor = GetExtractor(method->GetJSPandaFile()); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "GenerateCallFrame: extractor is null"; + return false; + } + + // location + std::unique_ptr location = std::make_unique(); + std::string url = extractor->GetSourceFile(method->GetMethodId()); + auto scriptFunc = [&location](PtScript *script) -> bool { + location->SetScriptId(script->GetScriptId()); + return true; + }; + if (!MatchScripts(scriptFunc, url, ScriptMatchType::URL)) { + LOG(ERROR, DEBUGGER) << "GenerateCallFrame: Unknown url: " << url; + return false; + } + auto callbackLineFunc = [&location](int32_t line) -> bool { + location->SetLine(line); + return true; + }; + auto callbackColumnFunc = [&location](int32_t column) -> bool { + location->SetColumn(column); + return true; + }; + File::EntityId methodId = method->GetMethodId(); + if (!extractor->MatchLineWithOffset(callbackLineFunc, methodId, DebuggerApi::GetBytecodeOffset(frameHandler)) || + !extractor->MatchColumnWithOffset(callbackColumnFunc, methodId, DebuggerApi::GetBytecodeOffset(frameHandler))) { + LOG(ERROR, DEBUGGER) << "GenerateCallFrame: unknown offset: " << DebuggerApi::GetBytecodeOffset(frameHandler); + return false; + } + + // scopeChain & this + std::unique_ptr thisObj = std::make_unique(); + thisObj->SetType(ObjectType::Undefined); + + std::vector> scopeChain; + scopeChain.emplace_back(GetLocalScopeChain(frameHandler, &thisObj)); + scopeChain.emplace_back(GetGlobalScopeChain()); + + // functionName + std::string functionName = DebuggerApi::ParseFunctionName(method); + + callFrame->SetCallFrameId(callFrameId) + .SetFunctionName(functionName) + .SetLocation(std::move(location)) + .SetUrl(url) + .SetScopeChain(std::move(scopeChain)) + .SetThis(std::move(thisObj)); + return true; +} + +std::unique_ptr DebuggerImpl::GetLocalScopeChain(const InterpretedFrameHandler *frameHandler, + std::unique_ptr *thisObj) +{ + auto localScope = std::make_unique(); + + JSMethod *method = DebuggerApi::GetMethod(frameHandler); + JSPtExtractor *extractor = GetExtractor(method->GetJSPandaFile()); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "GetScopeChain: extractor is null"; + return localScope; + } + + std::unique_ptr local = std::make_unique(); + Local localObj = ObjectRef::New(vm_); + local->SetType(ObjectType::Object) + .SetObjectId(runtime_->curObjectId_) + .SetClassName(ObjectClassName::Object) + .SetDescription(RemoteObject::ObjectDescription); + auto *sp = DebuggerApi::GetSp(frameHandler); + scopeObjects_[sp] = runtime_->curObjectId_; + runtime_->properties_[runtime_->curObjectId_++] = Global(vm_, localObj); + + Local thisVal = JSValueRef::Undefined(vm_); + GetLocalVariables(frameHandler, method, thisVal, localObj); + *thisObj = RemoteObject::FromTagged(vm_, thisVal); + runtime_->CacheObjectIfNeeded(thisVal, (*thisObj).get()); + + auto methodId = method->GetMethodId(); + const LineNumberTable &lines = extractor->GetLineNumberTable(methodId); + std::unique_ptr startLoc = std::make_unique(); + std::unique_ptr endLoc = std::make_unique(); + auto scriptFunc = [&startLoc, &endLoc, lines](PtScript *script) -> bool { + startLoc->SetScriptId(script->GetScriptId()) + .SetLine(lines.front().line) + .SetColumn(0); + endLoc->SetScriptId(script->GetScriptId()) + .SetLine(lines.back().line + 1) + .SetColumn(0); + return true; + }; + if (MatchScripts(scriptFunc, extractor->GetSourceFile(methodId), ScriptMatchType::URL)) { + localScope->SetType(Scope::Type::Local()) + .SetObject(std::move(local)) + .SetStartLocation(std::move(startLoc)) + .SetEndLocation(std::move(endLoc)); + } + + return localScope; +} + +void DebuggerImpl::GetLocalVariables(const InterpretedFrameHandler *frameHandler, const JSMethod *method, + Local &thisVal, Local &localObj) +{ + auto methodId = method->GetMethodId(); + auto *extractor = GetExtractor(method->GetJSPandaFile()); + Local value = JSValueRef::Undefined(vm_); + // in case of arrow function, which doesn't have this in local variable table + bool hasThis = false; + for (const auto &[varName, regIndex] : extractor->GetLocalVariableTable(methodId)) { + value = DebuggerApi::GetVRegValue(vm_, frameHandler, regIndex); + if (varName == "4newTarget") { + continue; + } + + if (varName == "this") { + thisVal = value; + hasThis = true; + continue; + } + Local name = JSValueRef::Undefined(vm_); + if (varName == "4funcObj") { + if (value->IsFunction()) { + auto funcName = Local(value)->GetName(vm_)->ToString(); + name = StringRef::NewFromUtf8(vm_, funcName.c_str()); + } else { + continue; + } + } else { + name = StringRef::NewFromUtf8(vm_, varName.c_str()); + } + PropertyAttribute descriptor(value, true, true, true); + localObj->DefineProperty(vm_, name, descriptor); + } + + // closure variables are stored in env + JSTaggedValue env = DebuggerApi::GetEnv(frameHandler); + if (env.IsTaggedArray() && DebuggerApi::GetBytecodeOffset(frameHandler) != 0) { + LexicalEnv *lexEnv = LexicalEnv::Cast(env.GetTaggedObject()); + if (lexEnv->GetScopeInfo().IsHole()) { + return; + } + auto ptr = JSNativePointer::Cast(lexEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer(); + auto *scopeDebugInfo = reinterpret_cast(ptr); + JSThread *thread = vm_->GetJSThread(); + for (const auto &info : scopeDebugInfo->scopeInfo) { + // skip possible duplicate variables both in local variable table and env + if (info.name == "4newTarget") { + continue; + } + value = JSNApiHelper::ToLocal( + JSHandle(thread, lexEnv->GetProperties(info.slot))); + if (info.name == "this") { + if (!hasThis) { + thisVal = value; + } + continue; + } + Local name = StringRef::NewFromUtf8(vm_, info.name.c_str()); + PropertyAttribute descriptor(value, true, true, true); + localObj->DefineProperty(vm_, name, descriptor); + } + } +} + +std::unique_ptr DebuggerImpl::GetGlobalScopeChain() +{ + auto globalScope = std::make_unique(); + + std::unique_ptr global = std::make_unique(); + global->SetType(ObjectType::Object) + .SetObjectId(runtime_->curObjectId_) + .SetClassName(ObjectClassName::Global) + .SetDescription(RemoteObject::GlobalDescription); + globalScope->SetType(Scope::Type::Global()).SetObject(std::move(global)); + runtime_->properties_[runtime_->curObjectId_++] = Global(vm_, JSNApi::GetGlobalObject(vm_)); + return globalScope; +} + +void DebuggerImpl::UpdateScopeObject(const InterpretedFrameHandler *frameHandler, + std::string_view varName, Local newVal) +{ + auto *sp = DebuggerApi::GetSp(frameHandler); + auto iter = scopeObjects_.find(sp); + if (iter == scopeObjects_.end()) { + LOG(ERROR, DEBUGGER) << "UpdateScopeObject: object not found"; + return; + } + + auto objectId = iter->second; + Local localObj = runtime_->properties_[objectId].ToLocal(vm_); + Local name = StringRef::NewFromUtf8(vm_, varName.data()); + if (localObj->Has(vm_, name)) { + LOG(DEBUG, DEBUGGER) << "UpdateScopeObject: set new value"; + PropertyAttribute descriptor(newVal, true, true, true); + localObj->DefineProperty(vm_, name, descriptor); + } else { + LOG(ERROR, DEBUGGER) << "UpdateScopeObject: not found " << varName; + } +} + +std::optional DebuggerImpl::CmptEvaluateValue(CallFrameId callFrameId, const std::string &expression, + std::unique_ptr *result) +{ + JSMethod *method = DebuggerApi::GetMethod(vm_); + if (method->IsNativeWithCallField()) { + *result = RemoteObject::FromTagged(vm_, + Exception::EvalError(vm_, StringRef::NewFromUtf8(vm_, "Native Frame not support."))); + return "Native Frame not support."; + } + JSPtExtractor *extractor = GetExtractor(method->GetJSPandaFile()); + if (extractor == nullptr) { + *result = RemoteObject::FromTagged(vm_, + Exception::EvalError(vm_, StringRef::NewFromUtf8(vm_, "Internal error."))); + return "Internal error."; + } + std::string varName = expression; + std::string varValue; + std::string::size_type indexEqual = expression.find_first_of('=', 0); + if (indexEqual != std::string::npos) { + varName = Trim(expression.substr(0, indexEqual)); + varValue = Trim(expression.substr(indexEqual + 1, expression.length())); + } + + Local name = StringRef::NewFromUtf8(vm_, varName.c_str()); + InterpretedFrameHandler *frameHandler = callFrameHandlers_[callFrameId].get(); + if (varValue.empty()) { + Local ret = DebuggerExecutor::GetValue(vm_, frameHandler, name); + if (!ret.IsEmpty() && !ret->IsException()) { + *result = RemoteObject::FromTagged(vm_, ret); + runtime_->CacheObjectIfNeeded(ret, (*result).get()); + return {}; + } + } else { + Local value = ConvertToLocal(varValue); + if (value.IsEmpty()) { + return "Unsupported expression."; + } + JsDebuggerManager *mgr = vm_->GetJsDebuggerManager(); + mgr->SetEvalFrameHandler(callFrameHandlers_[callFrameId]); + bool ret = DebuggerExecutor::SetValue(vm_, frameHandler, name, value); + mgr->SetEvalFrameHandler(nullptr); + if (ret) { + *result = RemoteObject::FromTagged(vm_, value); + return {}; + } + } + + *result = RemoteObject::FromTagged(vm_, + Exception::EvalError(vm_, StringRef::NewFromUtf8(vm_, "Unsupported expression."))); + return "Unsupported expression."; +} + +Local DebuggerImpl::ConvertToLocal(const std::string &varValue) +{ + Local taggedValue; + if (varValue == "false") { + taggedValue = JSValueRef::False(vm_); + } else if (varValue == "true") { + taggedValue = JSValueRef::True(vm_); + } else if (varValue == "undefined") { + taggedValue = JSValueRef::Undefined(vm_); + } else if (varValue[0] == '\"' && varValue[varValue.length() - 1] == '\"') { + // 2 : 2 means length + taggedValue = StringRef::NewFromUtf8(vm_, varValue.substr(1, varValue.length() - 2).c_str()); + } else { + auto begin = reinterpret_cast((varValue.c_str())); + auto end = begin + varValue.length(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + double d = DebuggerApi::StringToDouble(begin, end, 0); + if (!std::isnan(d)) { + taggedValue = NumberRef::New(vm_, d); + } + } + return taggedValue; +} + +bool DebuggerImpl::DecodeAndCheckBase64(const std::string &src, std::string &dest) +{ + dest.resize(base64::decoded_size(src.size())); + auto [numOctets, _] = base64::decode(dest.data(), src.data(), src.size()); + dest.resize(numOctets); + if (numOctets > File::MAGIC_SIZE && + memcmp(dest.data(), File::MAGIC.data(), File::MAGIC_SIZE) == 0) { + return true; + } + return false; +} } // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/agent/debugger_impl.h b/ecmascript/tooling/agent/debugger_impl.h index c30a9a3f4edc302db2cd20477a11f1c891f70cb4..e1c94318d25d514254c7bd9858d41757b7d24027 100644 --- a/ecmascript/tooling/agent/debugger_impl.h +++ b/ecmascript/tooling/agent/debugger_impl.h @@ -17,42 +17,91 @@ #define ECMASCRIPT_TOOLING_AGENT_DEBUGGER_IMPL_H #include "libpandabase/macros.h" -#include "ecmascript/tooling/agent/js_backend.h" +#include "ecmascript/tooling/agent/runtime_impl.h" +#include "ecmascript/tooling/backend/js_pt_hooks.h" #include "ecmascript/tooling/base/pt_params.h" +#include "ecmascript/tooling/backend/js_pt_extractor.h" #include "ecmascript/tooling/dispatcher.h" +#include "ecmascript/tooling/interface/js_debugger_manager.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::CString; - +namespace test { +class TestHooks; +} // namespace test class DebuggerImpl final { public: - explicit DebuggerImpl(std::unique_ptr backend) : backend_(std::move(backend)) {} - ~DebuggerImpl() = default; + DebuggerImpl(const EcmaVM *vm, ProtocolChannel *channel, RuntimeImpl *runtime); + ~DebuggerImpl(); + + // event + bool NotifyScriptParsed(ScriptId scriptId, const std::string &fileName); + bool NotifySingleStep(const JSPtLocation &location); + void NotifyPaused(std::optional location, PauseReason reason); + void NotifyPendingJobEntry(); - DispatchResponse Enable(std::unique_ptr params, UniqueDebuggerId *id); - DispatchResponse EvaluateOnCallFrame(std::unique_ptr params, + DispatchResponse Enable(const EnableParams ¶ms, UniqueDebuggerId *id); + DispatchResponse Disable(); + DispatchResponse EvaluateOnCallFrame(const EvaluateOnCallFrameParams ¶ms, std::unique_ptr *result); - DispatchResponse GetPossibleBreakpoints(std::unique_ptr params, - CVector> *outLocations); - DispatchResponse GetScriptSource(std::unique_ptr params, CString *source); + DispatchResponse GetPossibleBreakpoints(const GetPossibleBreakpointsParams ¶ms, + std::vector> *outLocations); + DispatchResponse GetScriptSource(const GetScriptSourceParams ¶ms, std::string *source); DispatchResponse Pause(); - DispatchResponse RemoveBreakpoint(std::unique_ptr params); - DispatchResponse Resume(std::unique_ptr params); + DispatchResponse RemoveBreakpoint(const RemoveBreakpointParams ¶ms); + DispatchResponse Resume(const ResumeParams ¶ms); DispatchResponse SetAsyncCallStackDepth(); - DispatchResponse SetBreakpointByUrl(std::unique_ptr params, CString *out_id, - CVector> *outLocations); - DispatchResponse SetPauseOnExceptions(std::unique_ptr params); - DispatchResponse StepInto(std::unique_ptr params); + DispatchResponse SetBreakpointByUrl(const SetBreakpointByUrlParams ¶ms, std::string *outId, + std::vector> *outLocations); + DispatchResponse SetPauseOnExceptions(const SetPauseOnExceptionsParams ¶ms); + DispatchResponse StepInto(const StepIntoParams ¶ms); DispatchResponse StepOut(); - DispatchResponse StepOver(std::unique_ptr params); + DispatchResponse StepOver(const StepOverParams ¶ms); DispatchResponse SetBlackboxPatterns(); + /** + * @brief: match first script and callback + * + * @return: true means matched and callback execute success + */ + template + bool MatchScripts(const Callback &cb, const std::string &matchStr, ScriptMatchType type) const + { + for (const auto &script : scripts_) { + std::string value; + switch (type) { + case ScriptMatchType::URL: { + value = script.second->GetUrl(); + break; + } + case ScriptMatchType::FILE_NAME: { + value = script.second->GetFileName(); + break; + } + case ScriptMatchType::HASH: { + value = script.second->GetHash(); + break; + } + default: { + return false; + } + } + if (matchStr == value) { + return cb(script.second.get()); + } + } + return false; + } + bool GenerateCallFrames(std::vector> *callFrames); + class DispatcherImpl final : public DispatcherBase { public: - DispatcherImpl(FrontEnd *frontend, std::unique_ptr debugger); + DispatcherImpl(ProtocolChannel *channel, std::unique_ptr debugger) + : DispatcherBase(channel), debugger_(std::move(debugger)) {} ~DispatcherImpl() override = default; + void Dispatch(const DispatchRequest &request) override; void Enable(const DispatchRequest &request); + void Disable(const DispatchRequest &request); void EvaluateOnCallFrame(const DispatchRequest &request); void GetPossibleBreakpoints(const DispatchRequest &request); void GetScriptSource(const DispatchRequest &request); @@ -72,7 +121,6 @@ public: NO_MOVE_SEMANTIC(DispatcherImpl); using AgentHandler = void (DebuggerImpl::DispatcherImpl::*)(const DispatchRequest &request); - CMap dispatcherTable_ {}; std::unique_ptr debugger_ {}; }; @@ -80,7 +128,61 @@ private: NO_COPY_SEMANTIC(DebuggerImpl); NO_MOVE_SEMANTIC(DebuggerImpl); - std::unique_ptr backend_ {nullptr}; + std::string Trim(const std::string &str); + JSPtExtractor *GetExtractor(const JSPandaFile *jsPandaFile); + JSPtExtractor *GetExtractor(const std::string &url); + std::optional CmptEvaluateValue(CallFrameId callFrameId, const std::string &expression, + std::unique_ptr *result); + bool GenerateCallFrame(CallFrame *callFrame, const InterpretedFrameHandler *frameHandler, CallFrameId frameId); + void SaveCallFrameHandler(const InterpretedFrameHandler *frameHandler); + std::unique_ptr GetLocalScopeChain(const InterpretedFrameHandler *frameHandler, + std::unique_ptr *thisObj); + std::unique_ptr GetGlobalScopeChain(); + void GetLocalVariables(const InterpretedFrameHandler *frameHandler, const JSMethod *method, + Local &thisVal, Local &localObj); + void CleanUpOnPaused(); + void UpdateScopeObject(const InterpretedFrameHandler *frameHandler, + std::string_view varName, Local newVal); + Local ConvertToLocal(const std::string &varValue); + bool DecodeAndCheckBase64(const std::string &src, std::string &dest); + bool IsSkipLine(const JSPtLocation &location); + + class Frontend { + public: + explicit Frontend(ProtocolChannel *channel) : channel_(channel) {} + + void BreakpointResolved(const EcmaVM *vm); + void Paused(const EcmaVM *vm, const tooling::Paused &paused); + void Resumed(const EcmaVM *vm); + void ScriptFailedToParse(const EcmaVM *vm); + void ScriptParsed(const EcmaVM *vm, const PtScript &script); + void WaitForDebugger(const EcmaVM *vm); + + private: + bool AllowNotify(const EcmaVM *vm) const; + + ProtocolChannel *channel_ {nullptr}; + }; + + const EcmaVM *vm_ {nullptr}; + Frontend frontend_; + + RuntimeImpl *runtime_ {nullptr}; + std::unique_ptr hooks_ {nullptr}; + JSDebugger *jsDebugger_ {nullptr}; + + std::unordered_map extractors_ {}; + std::unordered_map> scripts_ {}; + bool pauseOnException_ {false}; + bool pauseOnNextByteCode_ {false}; + std::unique_ptr singleStepper_ {nullptr}; + + std::unordered_map scopeObjects_ {}; + std::vector> callFrameHandlers_; + JsDebuggerManager::ObjectUpdaterFunc updaterFunc_ {nullptr}; + + friend class JSPtHooks; + friend class test::TestHooks; }; } // namespace panda::ecmascript::tooling #endif \ No newline at end of file diff --git a/ecmascript/tooling/agent/heapprofiler_impl.cpp b/ecmascript/tooling/agent/heapprofiler_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abdc6cd8181fd8e740c8f29c6a082eaf2aa78762 --- /dev/null +++ b/ecmascript/tooling/agent/heapprofiler_impl.cpp @@ -0,0 +1,337 @@ +/* + * 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/tooling/agent/heapprofiler_impl.h" + +namespace panda::ecmascript::tooling { +void HeapProfilerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request) +{ + static std::unordered_map dispatcherTable { + { "addInspectedHeapObject", &HeapProfilerImpl::DispatcherImpl::AddInspectedHeapObject }, + { "collectGarbage", &HeapProfilerImpl::DispatcherImpl::CollectGarbage }, + { "enable", &HeapProfilerImpl::DispatcherImpl::Enable }, + { "disable", &HeapProfilerImpl::DispatcherImpl::Disable }, + { "getHeapObjectId", &HeapProfilerImpl::DispatcherImpl::GetHeapObjectId }, + { "getObjectByHeapObjectId", &HeapProfilerImpl::DispatcherImpl::GetObjectByHeapObjectId }, + { "getSamplingProfile", &HeapProfilerImpl::DispatcherImpl::GetSamplingProfile }, + { "startSampling", &HeapProfilerImpl::DispatcherImpl::StartSampling }, + { "startTrackingHeapObjects", &HeapProfilerImpl::DispatcherImpl::StartTrackingHeapObjects }, + { "stopSampling", &HeapProfilerImpl::DispatcherImpl::StopSampling }, + { "stopTrackingHeapObjects", &HeapProfilerImpl::DispatcherImpl::StopTrackingHeapObjects }, + { "takeHeapSnapshot", &HeapProfilerImpl::DispatcherImpl::TakeHeapSnapshot } + }; + + const std::string &method = request.GetMethod(); + LOG(DEBUG, DEBUGGER) << "dispatch [" << method << "] to HeapProfilerImpl"; + auto entry = dispatcherTable.find(method); + if (entry != dispatcherTable.end() && entry->second != nullptr) { + (this->*(entry->second))(request); + } else { + SendResponse(request, DispatchResponse::Fail("Unknown method: " + method)); + } +} + +void HeapProfilerImpl::DispatcherImpl::AddInspectedHeapObject(const DispatchRequest &request) +{ + std::unique_ptr params = AddInspectedHeapObjectParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + DispatchResponse response = heapprofiler_->AddInspectedHeapObject(*params); + SendResponse(request, response); +} + +void HeapProfilerImpl::DispatcherImpl::CollectGarbage(const DispatchRequest &request) +{ + DispatchResponse response = heapprofiler_->CollectGarbage(); + SendResponse(request, response); +} + +void HeapProfilerImpl::DispatcherImpl::Enable(const DispatchRequest &request) +{ + DispatchResponse response = heapprofiler_->Enable(); + SendResponse(request, response); +} + +void HeapProfilerImpl::DispatcherImpl::Disable(const DispatchRequest &request) +{ + DispatchResponse response = heapprofiler_->Disable(); + SendResponse(request, response); +} + +void HeapProfilerImpl::DispatcherImpl::GetHeapObjectId(const DispatchRequest &request) +{ + std::unique_ptr params = GetHeapObjectIdParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + + HeapSnapshotObjectId objectId; + DispatchResponse response = heapprofiler_->GetHeapObjectId(*params, &objectId); + GetHeapObjectIdReturns result(std::move(objectId)); + SendResponse(request, response, result); +} + +void HeapProfilerImpl::DispatcherImpl::GetObjectByHeapObjectId(const DispatchRequest &request) +{ + std::unique_ptr params = GetObjectByHeapObjectIdParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + + std::unique_ptr remoteObjectResult; + DispatchResponse response = heapprofiler_->GetObjectByHeapObjectId(*params, &remoteObjectResult); + GetObjectByHeapObjectIdReturns result(std::move(remoteObjectResult)); + SendResponse(request, response, result); +} + +void HeapProfilerImpl::DispatcherImpl::GetSamplingProfile(const DispatchRequest &request) +{ + std::unique_ptr profile; + DispatchResponse response = heapprofiler_->GetSamplingProfile(&profile); + // The return value type of GetSamplingProfile is the same as of StopSampling. + StopSamplingReturns result(std::move(profile)); + SendResponse(request, response, result); +} + +void HeapProfilerImpl::DispatcherImpl::StartSampling(const DispatchRequest &request) +{ + std::unique_ptr params = StartSamplingParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + DispatchResponse response = heapprofiler_->StartSampling(*params); + SendResponse(request, response); +} + +void HeapProfilerImpl::DispatcherImpl::StartTrackingHeapObjects(const DispatchRequest &request) +{ + std::unique_ptr params = + StartTrackingHeapObjectsParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + DispatchResponse response = heapprofiler_->StartTrackingHeapObjects(*params); + SendResponse(request, response); +} + + +void HeapProfilerImpl::DispatcherImpl::StopSampling(const DispatchRequest &request) +{ + std::unique_ptr profile; + DispatchResponse response = heapprofiler_->StopSampling(&profile); + StopSamplingReturns result(std::move(profile)); + SendResponse(request, response, result); +} + +void HeapProfilerImpl::DispatcherImpl::StopTrackingHeapObjects(const DispatchRequest &request) +{ + std::unique_ptr params = StopTrackingHeapObjectsParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + DispatchResponse response = heapprofiler_->StopTrackingHeapObjects(*params); + SendResponse(request, response); +} + +void HeapProfilerImpl::DispatcherImpl::TakeHeapSnapshot(const DispatchRequest &request) +{ + std::unique_ptr params = StopTrackingHeapObjectsParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + DispatchResponse response = heapprofiler_->TakeHeapSnapshot(*params); + SendResponse(request, response); +} + +bool HeapProfilerImpl::Frontend::AllowNotify() const +{ + return channel_ != nullptr; +} + +void HeapProfilerImpl::Frontend::AddHeapSnapshotChunk(char *data, int32_t size) +{ + if (!AllowNotify()) { + return; + } + + tooling::AddHeapSnapshotChunk addHeapSnapshotChunk; + addHeapSnapshotChunk.GetChunk().resize(size); + for (int32_t i = 0; i < size; ++i) { + addHeapSnapshotChunk.GetChunk()[i] = data[i]; + } + + channel_->SendNotification(addHeapSnapshotChunk); +} + +void HeapProfilerImpl::Frontend::ReportHeapSnapshotProgress(int32_t done, int32_t total) +{ + if (!AllowNotify()) { + return; + } + + tooling::ReportHeapSnapshotProgress reportHeapSnapshotProgress; + reportHeapSnapshotProgress.SetDone(done).SetTotal(total); + if (done >= total) { + reportHeapSnapshotProgress.SetFinished(true); + } + channel_->SendNotification(reportHeapSnapshotProgress); +} + +void HeapProfilerImpl::Frontend::HeapStatsUpdate(HeapStat* updateData, int32_t count) +{ + if (!AllowNotify()) { + return; + } + std::vector statsDiff; + for (int32_t i = 0; i < count; ++i) { + statsDiff.emplace_back(updateData[i].index_); + statsDiff.emplace_back(updateData[i].count_); + statsDiff.emplace_back(updateData[i].size_); + } + tooling::HeapStatsUpdate heapStatsUpdate; + heapStatsUpdate.SetStatsUpdate(std::move(statsDiff)); + channel_->SendNotification(heapStatsUpdate); +} + +void HeapProfilerImpl::Frontend::LastSeenObjectId(int32_t lastSeenObjectId) +{ + if (!AllowNotify()) { + return; + } + + tooling::LastSeenObjectId lastSeenObjectIdEvent; + lastSeenObjectIdEvent.SetLastSeenObjectId(lastSeenObjectId); + int64_t timestamp = 0; + struct timeval tv = {0, 0}; + gettimeofday(&tv, nullptr); + const int THOUSAND = 1000; + timestamp = static_cast(tv.tv_usec + tv.tv_sec * THOUSAND * THOUSAND); + lastSeenObjectIdEvent.SetTimestamp(timestamp); + channel_->SendNotification(lastSeenObjectIdEvent); +} + +void HeapProfilerImpl::Frontend::ResetProfiles() +{ + if (!AllowNotify()) { + return; + } +} + +DispatchResponse HeapProfilerImpl::AddInspectedHeapObject( + [[maybe_unused]] const AddInspectedHeapObjectParams ¶ms) +{ + LOG(ERROR, DEBUGGER) << "AddInspectedHeapObject not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::CollectGarbage() +{ + LOG(ERROR, DEBUGGER) << "CollectGarbage not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::Enable() +{ + LOG(ERROR, DEBUGGER) << "Enable not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::Disable() +{ + LOG(ERROR, DEBUGGER) << "Disable not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::GetHeapObjectId([[maybe_unused]] const GetHeapObjectIdParams ¶ms, + HeapSnapshotObjectId *objectId) +{ + ASSERT(objectId != nullptr); + *objectId = 0; + LOG(ERROR, DEBUGGER) << "GetHeapObjectId not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::GetObjectByHeapObjectId( + [[maybe_unused]] const GetObjectByHeapObjectIdParams ¶ms, + [[maybe_unused]] std::unique_ptr *remoteObjectResult) +{ + LOG(ERROR, DEBUGGER) << "GetObjectByHeapObjectId not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::GetSamplingProfile([[maybe_unused]]std::unique_ptr *profile) +{ + LOG(ERROR, DEBUGGER) << "GetSamplingProfile not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::StartSampling([[maybe_unused]]const StartSamplingParams ¶ms) +{ + LOG(ERROR, DEBUGGER) << "StartSampling not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::StartTrackingHeapObjects( + [[maybe_unused]]const StartTrackingHeapObjectsParams ¶ms) +{ + bool result = panda::DFXJSNApi::StartHeapTracking(vm_, INTERVAL, true, &stream_); + if (result) { + return DispatchResponse::Ok(); + } else { + return DispatchResponse::Fail("StartHeapTracking fail"); + } +} + +DispatchResponse HeapProfilerImpl::StopSampling([[maybe_unused]]std::unique_ptr *profile) +{ + LOG(ERROR, DEBUGGER) << "StopSampling not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse HeapProfilerImpl::StopTrackingHeapObjects(const StopTrackingHeapObjectsParams ¶ms) +{ + bool result = false; + if (params.GetReportProgress()) { + HeapProfilerProgress progress(&frontend_); + result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, &progress); + } else { + result = panda::DFXJSNApi::StopHeapTracking(vm_, &stream_, nullptr); + } + if (result) { + return DispatchResponse::Ok(); + } else { + return DispatchResponse::Fail("StopHeapTracking fail"); + } +} + +DispatchResponse HeapProfilerImpl::TakeHeapSnapshot(const StopTrackingHeapObjectsParams ¶ms) +{ + if (params.GetReportProgress()) { + HeapProfilerProgress progress(&frontend_); + panda::DFXJSNApi::DumpHeapSnapshot(vm_, 0, &stream_, &progress, true); + } else { + panda::DFXJSNApi::DumpHeapSnapshot(vm_, 0, &stream_, nullptr, true); + } + return DispatchResponse::Ok(); +} +} // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/agent/heapprofiler_impl.h b/ecmascript/tooling/agent/heapprofiler_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..e74e6241acc97533969d46a98cc188d2af51e166 --- /dev/null +++ b/ecmascript/tooling/agent/heapprofiler_impl.h @@ -0,0 +1,173 @@ +/* + * 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_AGENT_HEAPPROFILER_IMPL_H +#define ECMASCRIPT_TOOLING_AGENT_HEAPPROFILER_IMPL_H + +#include +#include "libpandabase/macros.h" +#include "ecmascript/tooling/base/pt_params.h" +#include "ecmascript/tooling/base/pt_events.h" +#include "ecmascript/tooling/base/pt_returns.h" +#include "ecmascript/tooling/dispatcher.h" +#include "ecmascript/tooling/interface/stream.h" +#include "ecmascript/tooling/interface/progress.h" +#include "ecmascript/tooling/protocol_handler.h" +#include "ecmascript/tooling/protocol_channel.h" +#include "ecmascript/napi/include/dfx_jsnapi.h" +#include "libpandabase/utils/logger.h" + +static const double INTERVAL = 0.05; + +namespace panda::ecmascript::tooling { +class HeapProfilerImpl final { +public: + explicit HeapProfilerImpl(const EcmaVM *vm, ProtocolChannel *channel) + : vm_(vm), frontend_(channel), stream_(&frontend_) {} + ~HeapProfilerImpl() = default; + + DispatchResponse AddInspectedHeapObject(const AddInspectedHeapObjectParams ¶ms); + DispatchResponse CollectGarbage(); + DispatchResponse Enable(); + DispatchResponse Disable(); + DispatchResponse GetHeapObjectId(const GetHeapObjectIdParams ¶ms, HeapSnapshotObjectId *objectId); + DispatchResponse GetObjectByHeapObjectId(const GetObjectByHeapObjectIdParams ¶ms, + std::unique_ptr *remoteObjectResult); + DispatchResponse GetSamplingProfile(std::unique_ptr *profile); + DispatchResponse StartSampling(const StartSamplingParams ¶ms); + DispatchResponse StartTrackingHeapObjects(const StartTrackingHeapObjectsParams ¶ms); + DispatchResponse StopSampling(std::unique_ptr *profile); + DispatchResponse StopTrackingHeapObjects(const StopTrackingHeapObjectsParams ¶ms); + // The params type of TakeHeapSnapshot is the same as of StopTrackingHeapObjects. + DispatchResponse TakeHeapSnapshot(const StopTrackingHeapObjectsParams ¶ms); + + class DispatcherImpl final : public DispatcherBase { + public: + DispatcherImpl(ProtocolChannel *channel, std::unique_ptr heapprofiler) + : DispatcherBase(channel), heapprofiler_(std::move(heapprofiler)) {} + ~DispatcherImpl() override = default; + + void Dispatch(const DispatchRequest &request) override; + void AddInspectedHeapObject(const DispatchRequest &request); + void CollectGarbage(const DispatchRequest &request); + void Enable(const DispatchRequest &request); + void Disable(const DispatchRequest &request); + void GetHeapObjectId(const DispatchRequest &request); + void GetObjectByHeapObjectId(const DispatchRequest &request); + void GetSamplingProfile(const DispatchRequest &request); + void StartSampling(const DispatchRequest &request); + void StartTrackingHeapObjects(const DispatchRequest &request); + void StopSampling(const DispatchRequest &request); + void StopTrackingHeapObjects(const DispatchRequest &request); + void TakeHeapSnapshot(const DispatchRequest &request); + + private: + NO_COPY_SEMANTIC(DispatcherImpl); + NO_MOVE_SEMANTIC(DispatcherImpl); + + using AgentHandler = void (HeapProfilerImpl::DispatcherImpl::*)(const DispatchRequest &request); + std::unique_ptr heapprofiler_ {}; + }; + +private: + NO_COPY_SEMANTIC(HeapProfilerImpl); + NO_MOVE_SEMANTIC(HeapProfilerImpl); + + class Frontend { + public: + explicit Frontend(ProtocolChannel *channel) : channel_(channel) {} + + void AddHeapSnapshotChunk(char *data, int32_t size); + void ReportHeapSnapshotProgress(int32_t done, int32_t total); + void HeapStatsUpdate(HeapStat* updateData, int32_t count); + void LastSeenObjectId(int32_t lastSeenObjectId); + void ResetProfiles(); + + private: + bool AllowNotify() const; + + ProtocolChannel *channel_ {nullptr}; + }; + + class HeapProfilerStream final : public Stream { + public: + explicit HeapProfilerStream(Frontend *frontend) + : frontend_(frontend) {} + + void EndOfStream() override {} + int GetSize() override + { + static const int heapProfilerChunkSise = 102400; + return heapProfilerChunkSise; + } + bool WriteChunk(char *data, int32_t size) override + { + if (!Good()) { + return false; + } + frontend_->AddHeapSnapshotChunk(data, size); + return true; + } + bool Good() override + { + return frontend_ != nullptr; + } + + void UpdateHeapStats(HeapStat* updateData, int32_t count) override + { + if (!Good()) { + return; + } + frontend_->HeapStatsUpdate(updateData, count); + } + + void UpdateLastSeenObjectId(int32_t lastSeenObjectId) override + { + if (!Good()) { + return; + } + frontend_->LastSeenObjectId(lastSeenObjectId); + } + + private: + NO_COPY_SEMANTIC(HeapProfilerStream); + NO_MOVE_SEMANTIC(HeapProfilerStream); + + Frontend *frontend_ {nullptr}; + }; + + class HeapProfilerProgress final : public Progress { + public: + explicit HeapProfilerProgress(Frontend *frontend) + : frontend_(frontend) {} + + void ReportProgress(int32_t done, int32_t total) override + { + frontend_->ReportHeapSnapshotProgress(done, total); + } + + private: + NO_COPY_SEMANTIC(HeapProfilerProgress); + NO_MOVE_SEMANTIC(HeapProfilerProgress); + + Frontend *frontend_ {nullptr}; + }; + + const EcmaVM *vm_ {nullptr}; + Frontend frontend_; + HeapProfilerStream stream_; +}; +} // namespace panda::ecmascript::tooling +#endif \ No newline at end of file diff --git a/ecmascript/tooling/agent/js_backend.cpp b/ecmascript/tooling/agent/js_backend.cpp deleted file mode 100644 index b4dc7a4763174f1207a25255577e586a70b22b72..0000000000000000000000000000000000000000 --- a/ecmascript/tooling/agent/js_backend.cpp +++ /dev/null @@ -1,913 +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. - */ - -#include "js_backend.h" - -#include -#include - -#include "ecmascript/tooling/base/pt_events.h" -#include "ecmascript/tooling/front_end.h" -#include "ecmascript/tooling/protocol_handler.h" -#include "ecmascript/napi/jsnapi_helper-inl.h" -#include "libpandafile/class_data_accessor-inl.h" - -namespace panda::ecmascript::tooling { -using namespace boost::beast::detail; -using namespace std::placeholders; - -using ObjectType = RemoteObject::TypeName; -using ObjectSubType = RemoteObject::SubTypeName; -using ObjectClassName = RemoteObject::ClassName; - -const std::string DATA_APP_PATH = "/data/"; - -JSBackend::JSBackend(FrontEnd *frontend) : frontend_(frontend) -{ - ecmaVm_ = static_cast(frontend)->GetEcmaVM(); - hooks_ = std::make_unique(this); - - debugger_ = DebuggerApi::CreateJSDebugger(ecmaVm_); - DebuggerApi::InitJSDebugger(debugger_); - DebuggerApi::RegisterHooks(debugger_, hooks_.get()); - - updaterFunc_ = std::bind(&JSBackend::UpdateScopeObject, this, _1, _2, _3); - ecmaVm_->GetJsDebuggerManager()->SetLocalScopeUpdater(&updaterFunc_); -} - -JSBackend::JSBackend(const EcmaVM *vm) : ecmaVm_(vm) -{ - // For testcases - debugger_ = DebuggerApi::CreateJSDebugger(ecmaVm_); -} - -JSBackend::~JSBackend() -{ - DebuggerApi::DestroyJSDebugger(debugger_); -} - -void JSBackend::NotifyPaused(std::optional location, PauseReason reason) -{ - if (!pauseOnException_ && reason == EXCEPTION) { - return; - } - - Local exception = DebuggerApi::GetAndClearException(ecmaVm_); - - CVector hitBreakpoints; - if (location.has_value()) { - BreakpointDetails detail; - PtJSExtractor *extractor = nullptr; - auto scriptFunc = [this, &extractor, &detail](PtScript *script) -> bool { - detail.url_ = script->GetUrl(); - extractor = GetExtractor(detail.url_); - return true; - }; - auto callbackFunc = [&detail](size_t line, size_t column) -> bool { - detail.line_ = line; - detail.column_ = column; - return true; - }; - if (!MatchScripts(scriptFunc, location->GetPandaFile(), ScriptMatchType::FILE_NAME) || extractor == nullptr || - !extractor->MatchWithOffset(callbackFunc, location->GetMethodId(), location->GetBytecodeOffset())) { - LOG(ERROR, DEBUGGER) << "NotifyPaused: unknown " << location->GetPandaFile(); - return; - } - hitBreakpoints.emplace_back(BreakpointDetails::ToString(detail)); - } - - // Do something cleaning on paused - CleanUpOnPaused(); - - // Notify paused event - CVector> callFrames; - if (!GenerateCallFrames(&callFrames)) { - LOG(ERROR, DEBUGGER) << "NotifyPaused: GenerateCallFrames failed"; - return; - } - std::unique_ptr paused = std::make_unique(); - paused->SetCallFrames(std::move(callFrames)).SetReason(reason).SetHitBreakpoints(std::move(hitBreakpoints)); - if (reason == EXCEPTION && exception->IsError()) { - std::unique_ptr tmpException = RemoteObject::FromTagged(ecmaVm_, exception); - paused->SetData(std::move(tmpException)); - } - frontend_->SendNotification(ecmaVm_, std::move(paused)); - - // Waiting for Debugger - frontend_->WaitForDebugger(); - if (!exception->IsHole()) { - DebuggerApi::SetException(ecmaVm_, exception); - } -} - -void JSBackend::NotifyResume() -{ - frontend_->RunIfWaitingForDebugger(); - // Notify resumed event - frontend_->SendNotification(ecmaVm_, std::make_unique()); -} - -void JSBackend::NotifyAllScriptParsed() -{ - for (auto &script : scripts_) { - if (frontend_ != nullptr) { - frontend_->SendNotification(ecmaVm_, ScriptParsed::Create(script.second)); - } - } -} - -bool JSBackend::NotifyScriptParsed(int32_t scriptId, const CString &fileName) -{ - auto scriptFunc = []([[maybe_unused]] PtScript *script) -> bool { - return true; - }; - if (MatchScripts(scriptFunc, fileName, ScriptMatchType::FILE_NAME)) { - LOG(WARNING, DEBUGGER) << "NotifyScriptParsed: already loaded: " << fileName; - return false; - } - const panda_file::File *pfs = DebuggerApi::FindPandaFile(ecmaVm_, fileName); - if (pfs == nullptr) { - LOG(WARNING, DEBUGGER) << "NotifyScriptParsed: unknown file: " << 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: Unsupport file: " << fileName; - return false; - } - - CString url; - CString source; - PtJSExtractor *extractor = GenerateExtractor(pfs); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "NotifyScriptParsed: Unsupport file: " << fileName; - return false; - } - - const uint32_t MIN_SOURCE_CODE_LENGTH = 5; // maybe return 'ANDA' when source code is empty - for (const auto &method : extractor->GetMethodIdList()) { - source = CString(extractor->GetSourceCode(method)); - // only main function has source code - if (source.size() >= MIN_SOURCE_CODE_LENGTH) { - url = CString(extractor->GetSourceFile(method)); - break; - } - } - if (url.empty()) { - LOG(ERROR, DEBUGGER) << "NotifyScriptParsed: invalid file: " << fileName; - return false; - } - // Notify script parsed event - std::unique_ptr script = std::make_unique(scriptId, fileName, url, source); - - if (frontend_ != nullptr) { - frontend_->SendNotification(ecmaVm_, ScriptParsed::Create(script)); - } - - // Store parsed script in map - scripts_[script->GetScriptId()] = std::move(script); - return true; -} - -bool JSBackend::StepComplete(const JSPtLocation &location) -{ - PtJSExtractor *extractor = nullptr; - auto scriptFunc = [this, &extractor](PtScript *script) -> bool { - extractor = GetExtractor(script->GetUrl()); - return true; - }; - auto callbackFunc = [](size_t line, [[maybe_unused]] size_t column) -> bool { - return line == static_cast(SPECIAL_LINE_MARK); - }; - if (MatchScripts(scriptFunc, location.GetPandaFile(), ScriptMatchType::FILE_NAME) && extractor != nullptr && - extractor->MatchWithOffset(callbackFunc, location.GetMethodId(), location.GetBytecodeOffset())) { - LOG(INFO, DEBUGGER) << "StepComplete: skip -1"; - return false; - } - - if (pauseOnNextByteCode_ || - (singleStepper_ != nullptr && singleStepper_->StepComplete(location.GetBytecodeOffset()))) { - LOG(INFO, DEBUGGER) << "StepComplete: pause on current byte_code"; - pauseOnNextByteCode_ = false; - return true; - } - - return false; -} - -std::optional JSBackend::GetPossibleBreakpoints(Location *start, [[maybe_unused]] Location *end, - CVector> *locations) -{ - PtJSExtractor *extractor = nullptr; - auto scriptFunc = [this, &extractor](PtScript *script) -> bool { - extractor = GetExtractor(script->GetUrl()); - return true; - }; - if (!MatchScripts(scriptFunc, start->GetScriptId(), ScriptMatchType::SCRIPT_ID) || extractor == nullptr) { - return "Unknown file name."; - } - - size_t line = start->GetLine(); - size_t column = start->GetColumn(); - auto callbackFunc = []([[maybe_unused]] File::EntityId id, [[maybe_unused]] uint32_t offset) -> bool { - return true; - }; - if (extractor->MatchWithLocation(callbackFunc, line, column)) { - std::unique_ptr location = std::make_unique(); - location->SetScriptId(start->GetScriptId()).SetLine(line).SetColumn(column); - locations->emplace_back(std::move(location)); - } - - return {}; -} - -std::optional JSBackend::SetBreakpointByUrl(const CString &url, size_t lineNumber, - size_t columnNumber, const std::optional &condition, CString *outId, - CVector> *outLocations) -{ - PtJSExtractor *extractor = GetExtractor(url); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: extractor is null"; - return "Unknown file name."; - } - - CString scriptId; - CString fileName; - auto scriptFunc = [&scriptId, &fileName](PtScript *script) -> bool { - scriptId = script->GetScriptId(); - fileName = script->GetFileName(); - return true; - }; - if (!MatchScripts(scriptFunc, url, ScriptMatchType::URL)) { - LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: Unknown url: " << url; - return "Unknown file name."; - } - - auto callbackFunc = [this, fileName, &condition](File::EntityId id, uint32_t offset) -> bool { - JSPtLocation location {fileName.c_str(), id, offset}; - Local condFuncRef = FunctionRef::Undefined(ecmaVm_); - if (condition.has_value() && !condition.value().empty()) { - CString dest; - if (!DecodeAndCheckBase64(condition.value(), dest)) { - LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: base64 decode failed"; - return false; - } - condFuncRef = DebuggerApi::GenerateFuncFromBuffer(ecmaVm_, dest.data(), dest.size()); - if (condFuncRef->IsUndefined()) { - LOG(ERROR, DEBUGGER) << "SetBreakpointByUrl: generate function failed"; - return false; - } - } - return DebuggerApi::SetBreakpoint(debugger_, location, condFuncRef); - }; - if (!extractor->MatchWithLocation(callbackFunc, lineNumber, columnNumber)) { - LOG(ERROR, DEBUGGER) << "failed to set breakpoint location number: " << lineNumber << ":" << columnNumber; - return "Breakpoint not found."; - } - - BreakpointDetails metaData{lineNumber, 0, url}; - *outId = BreakpointDetails::ToString(metaData); - *outLocations = CVector>(); - std::unique_ptr location = std::make_unique(); - location->SetScriptId(scriptId).SetLine(lineNumber).SetColumn(0); - outLocations->emplace_back(std::move(location)); - return {}; -} - -std::optional JSBackend::RemoveBreakpoint(const BreakpointDetails &metaData) -{ - PtJSExtractor *extractor = GetExtractor(metaData.url_); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "RemoveBreakpoint: extractor is null"; - return "Unknown file name."; - } - - CString fileName; - auto scriptFunc = [&fileName](PtScript *script) -> bool { - fileName = script->GetFileName(); - return true; - }; - if (!MatchScripts(scriptFunc, metaData.url_, ScriptMatchType::URL)) { - LOG(ERROR, DEBUGGER) << "RemoveBreakpoint: Unknown url: " << metaData.url_; - return "Unknown file name."; - } - - auto callbackFunc = [this, fileName](File::EntityId id, uint32_t offset) -> bool { - JSPtLocation location {fileName.c_str(), id, offset}; - return DebuggerApi::RemoveBreakpoint(debugger_, location); - }; - if (!extractor->MatchWithLocation(callbackFunc, metaData.line_, metaData.column_)) { - LOG(ERROR, DEBUGGER) << "failed to set breakpoint location number: " - << metaData.line_ << ":" << metaData.column_; - return "Breakpoint not found."; - } - - LOG(INFO, DEBUGGER) << "remove breakpoint line number:" << metaData.line_; - return {}; -} - -std::optional JSBackend::Pause() -{ - pauseOnNextByteCode_ = true; - return {}; -} - -std::optional JSBackend::Resume() -{ - singleStepper_.reset(); - - NotifyResume(); - return {}; -} - -std::optional JSBackend::StepInto() -{ - JSMethod *method = DebuggerApi::GetMethod(ecmaVm_); - PtJSExtractor *extractor = GetExtractor(method->GetPandaFile()); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "StepInto: extractor is null"; - return "Unknown file name."; - } - - singleStepper_ = extractor->GetStepIntoStepper(ecmaVm_); - - NotifyResume(); - return {}; -} - -std::optional JSBackend::StepOver() -{ - JSMethod *method = DebuggerApi::GetMethod(ecmaVm_); - PtJSExtractor *extractor = GetExtractor(method->GetPandaFile()); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "StepOver: extractor is null"; - return "Unknown file name."; - } - - singleStepper_ = extractor->GetStepOverStepper(ecmaVm_); - - NotifyResume(); - return {}; -} - -std::optional JSBackend::StepOut() -{ - JSMethod *method = DebuggerApi::GetMethod(ecmaVm_); - PtJSExtractor *extractor = GetExtractor(method->GetPandaFile()); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "StepOut: extractor is null"; - return "Unknown file name."; - } - - singleStepper_ = extractor->GetStepOutStepper(ecmaVm_); - - NotifyResume(); - return {}; -} - -std::optional JSBackend::CmptEvaluateValue(const CString &callFrameId, const CString &expression, - std::unique_ptr *result) -{ - JSMethod *method = DebuggerApi::GetMethod(ecmaVm_); - if (method->IsNative()) { - *result = RemoteObject::FromTagged(ecmaVm_, - Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, "Runtime internal error"))); - return "Native Frame not support."; - } - DebugInfoExtractor *extractor = GetExtractor(method->GetPandaFile()); - if (extractor == nullptr) { - *result = RemoteObject::FromTagged(ecmaVm_, - Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, "Runtime internal error"))); - return "Internal error."; - } - CString varName = expression; - CString varValue; - CString::size_type indexEqual = expression.find_first_of('=', 0); - if (indexEqual != CString::npos) { - varName = Trim(expression.substr(0, indexEqual)); - varValue = Trim(expression.substr(indexEqual + 1, expression.length())); - } - - if (!varValue.empty() && callFrameId != "0") { - *result = RemoteObject::FromTagged(ecmaVm_, - Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, "Native Frame not support."))); - return "Native Frame not support."; - } - - 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; - } - } - if (regIndex != -1) { - if (varValue.empty()) { - return GetVregValue(regIndex, result); - } - return SetVregValue(regIndex, varValue, result); - } - int32_t level = 0; - uint32_t slot = 0; - if (!DebuggerApi::EvaluateLexicalValue(ecmaVm_, varName, level, slot)) { - *result = RemoteObject::FromTagged(ecmaVm_, - Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, "Unknow input params"))); - return "Unsupported expression."; - } - if (varValue.empty()) { - return GetLexicalValue(level, slot, result); - } - return SetLexicalValue(level, slot, varValue, result); -} - -std::optional JSBackend::EvaluateValue(const CString &callFrameId, const CString &expression, - std::unique_ptr *result) -{ - size_t frameId = static_cast(DebuggerApi::CStringToULL(callFrameId)); - if (frameId < 0 || frameId >= callFrameHandlers_.size()) { - return "Invalid callFrameId."; - } - - CString dest; - if (!DecodeAndCheckBase64(expression, dest)) { - LOG(ERROR, DEBUGGER) << "EvaluateValue: base64 decode failed"; - return CmptEvaluateValue(callFrameId, expression, result); - } - - auto funcRef = DebuggerApi::GenerateFuncFromBuffer(ecmaVm_, dest.data(), dest.size()); - auto res = DebuggerApi::EvaluateViaFuncCall(const_cast(ecmaVm_), funcRef, - callFrameHandlers_[frameId]); - - CString msg; - if (DebuggerApi::HandleUncaughtException(ecmaVm_, msg)) { - LOG(ERROR, DEBUGGER) << "EvaluateValue: has pending exception"; - *result = RemoteObject::FromTagged(ecmaVm_, - Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, msg.data()))); - return msg; - } - - CacheObjectIfNeeded(res, result); - return {}; -} - -CString JSBackend::Trim(const CString &str) -{ - CString ret = str; - // If ret has only ' ', remove all charactors. - ret.erase(ret.find_last_not_of(' ') + 1); - // If ret has only ' ', remove all charactors. - ret.erase(0, ret.find_first_not_of(' ')); - return ret; -} - -PtJSExtractor *JSBackend::GenerateExtractor(const panda_file::File *file) -{ - if (file->GetFilename().substr(0, DATA_APP_PATH.length()) != DATA_APP_PATH) { - return nullptr; - } - auto extractor = std::make_unique(file); - PtJSExtractor *res = extractor.get(); - extractors_[file->GetFilename()] = std::move(extractor); - return res; -} - -PtJSExtractor *JSBackend::GetExtractor(const panda_file::File *file) -{ - const std::string fileName = file->GetFilename(); - if (extractors_.find(fileName) == extractors_.end()) { - return nullptr; - } - - return extractors_[fileName].get(); -} - -PtJSExtractor *JSBackend::GetExtractor(const CString &url) -{ - for (const auto &iter : extractors_) { - auto methods = iter.second->GetMethodIdList(); - for (const auto &method : methods) { - auto sourceFile = iter.second->GetSourceFile(method); - if (sourceFile == url) { - return iter.second.get(); - } - } - } - return nullptr; -} - -bool JSBackend::GenerateCallFrames(CVector> *callFrames) -{ - int32_t callFrameId = 0; - auto walkerFunc = [this, &callFrameId, &callFrames](const InterpretedFrameHandler *frameHandler) -> StackState { - JSMethod *method = DebuggerApi::GetMethod(frameHandler); - if (method->IsNative()) { - LOG(INFO, DEBUGGER) << "GenerateCallFrames: Skip CFrame and Native method"; - return StackState::CONTINUE; - } - std::unique_ptr callFrame = std::make_unique(); - if (!GenerateCallFrame(callFrame.get(), frameHandler, callFrameId)) { - if (callFrameId == 0) { - return StackState::FAILED; - } - } else { - SaveCallFrameHandler(frameHandler); - callFrames->emplace_back(std::move(callFrame)); - callFrameId++; - } - return StackState::CONTINUE; - }; - return DebuggerApi::StackWalker(ecmaVm_, walkerFunc); -} - -void JSBackend::SaveCallFrameHandler(const InterpretedFrameHandler *frameHandler) -{ - auto handlerPtr = DebuggerApi::NewFrameHandler(ecmaVm_); - *handlerPtr = *frameHandler; - callFrameHandlers_.emplace_back(handlerPtr); -} - -bool JSBackend::GenerateCallFrame(CallFrame *callFrame, - const InterpretedFrameHandler *frameHandler, int32_t callFrameId) -{ - JSMethod *method = DebuggerApi::GetMethod(frameHandler); - auto *pf = method->GetPandaFile(); - PtJSExtractor *extractor = GetExtractor(pf); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "GenerateCallFrame: extractor is null"; - return false; - } - - // location - std::unique_ptr location = std::make_unique(); - CString url = extractor->GetSourceFile(method->GetFileId()); - auto scriptFunc = [&location](PtScript *script) -> bool { - location->SetScriptId(script->GetScriptId()); - return true; - }; - if (!MatchScripts(scriptFunc, url, ScriptMatchType::URL)) { - LOG(ERROR, DEBUGGER) << "GenerateCallFrame: Unknown url: " << url; - return false; - } - auto callbackFunc = [&location](size_t line, size_t column) -> bool { - location->SetLine(line); - location->SetColumn(column); - return true; - }; - if (!extractor->MatchWithOffset(callbackFunc, method->GetFileId(), DebuggerApi::GetBytecodeOffset(frameHandler))) { - LOG(ERROR, DEBUGGER) << "GenerateCallFrame: unknown offset: " << DebuggerApi::GetBytecodeOffset(frameHandler); - return false; - } - - // scopeChain & this - std::unique_ptr thisObj = std::make_unique(); - thisObj->SetType(ObjectType::Undefined); - - CVector> scopeChain; - scopeChain.emplace_back(GetLocalScopeChain(frameHandler, &thisObj)); - scopeChain.emplace_back(GetGlobalScopeChain()); - - // functionName - CString functionName = DebuggerApi::ParseFunctionName(method); - - callFrame->SetCallFrameId(DebuggerApi::ToCString(callFrameId)) - .SetFunctionName(functionName) - .SetLocation(std::move(location)) - .SetUrl(url) - .SetScopeChain(std::move(scopeChain)) - .SetThis(std::move(thisObj)); - return true; -} - -std::unique_ptr JSBackend::GetLocalScopeChain(const InterpretedFrameHandler *frameHandler, - std::unique_ptr *thisObj) -{ - auto localScope = std::make_unique(); - - JSMethod *method = DebuggerApi::GetMethod(frameHandler); - PtJSExtractor *extractor = GetExtractor(method->GetPandaFile()); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "GetScopeChain: extractor is null"; - return localScope; - } - - std::unique_ptr local = std::make_unique(); - Local localObj(local->NewObject(ecmaVm_)); - local->SetType(ObjectType::Object) - .SetObjectId(curObjectId_) - .SetClassName(ObjectClassName::Object) - .SetDescription(RemoteObject::ObjectDescription); - auto *sp = DebuggerApi::GetSp(frameHandler); - scopeObjects_[sp] = curObjectId_; - propertiesPair_[curObjectId_++] = Global(ecmaVm_, localObj); - - Local thisVal = JSValueRef::Undefined(ecmaVm_); - GetLocalVariables(frameHandler, method, thisVal, localObj); - CacheObjectIfNeeded(thisVal, thisObj); - - panda_file::File::EntityId methodId = method->GetFileId(); - const panda_file::LineNumberTable &lines = extractor->GetLineNumberTable(methodId); - std::unique_ptr startLoc = std::make_unique(); - std::unique_ptr endLoc = std::make_unique(); - auto scriptFunc = [&startLoc, &endLoc, lines](PtScript *script) -> bool { - startLoc->SetScriptId(script->GetScriptId()) - .SetLine(lines.front().line) - .SetColumn(0); - endLoc->SetScriptId(script->GetScriptId()) - .SetLine(lines.back().line + 1) - .SetColumn(0); - return true; - }; - if (MatchScripts(scriptFunc, extractor->GetSourceFile(methodId), ScriptMatchType::URL)) { - localScope->SetType(Scope::Type::Local()) - .SetObject(std::move(local)) - .SetStartLocation(std::move(startLoc)) - .SetEndLocation(std::move(endLoc)); - } - - return localScope; -} - -void JSBackend::GetLocalVariables(const InterpretedFrameHandler *frameHandler, const JSMethod *method, - Local &thisVal, Local &localObj) -{ - auto methodId = method->GetFileId(); - auto *extractor = GetExtractor(method->GetPandaFile()); - Local value = JSValueRef::Undefined(ecmaVm_); - Local name = JSValueRef::Undefined(ecmaVm_); - bool hasThis = false; - for (const auto &var: extractor->GetLocalVariableTable(methodId)) { - value = DebuggerApi::GetVRegValue(ecmaVm_, frameHandler, var.reg_number); - if (var.name == "4newTarget") { - continue; - } else if (var.name == "this") { - thisVal = value; - hasThis = true; - } else { - if (var.name == "4funcObj" && value->IsFunction()) { - name = Local(value)->GetName(ecmaVm_); - } else { - name = StringRef::NewFromUtf8(ecmaVm_, var.name.c_str()); - } - PropertyAttribute descriptor(value, true, true, true); - localObj->DefineProperty(ecmaVm_, name, descriptor); - } - } - if (!hasThis) { - thisVal = DebuggerApi::GetLexicalValueInfo(ecmaVm_, "this"); - } - - // closure variables are stored in env - DebuggerApi::SetClosureVariables(ecmaVm_, frameHandler, localObj); -} - -void JSBackend::UpdateScopeObject(const InterpretedFrameHandler *frameHandler, - const CString &varName, const Local &newVal) -{ - auto *sp = DebuggerApi::GetSp(frameHandler); - auto iter = scopeObjects_.find(sp); - if (iter == scopeObjects_.end()) { - LOG(ERROR, DEBUGGER) << "UpdateScopeObject: object not found"; - return; - } - - auto objectId = iter->second; - Local localObj = propertiesPair_[objectId].ToLocal(ecmaVm_); - Local name = StringRef::NewFromUtf8(ecmaVm_, varName.c_str()); - if (localObj->Has(ecmaVm_, name)) { - LOG(DEBUG, DEBUGGER) << "UpdateScopeObject: set new value"; - PropertyAttribute descriptor(newVal, true, true, true); - localObj->DefineProperty(ecmaVm_, name, descriptor); - } else { - LOG(ERROR, DEBUGGER) << "UpdateScopeObject: not found " << varName; - } -} -std::unique_ptr JSBackend::GetGlobalScopeChain() -{ - auto globalScope = std::make_unique(); - - std::unique_ptr global = std::make_unique(); - global->SetType(ObjectType::Object) - .SetObjectId(curObjectId_) - .SetClassName(ObjectClassName::Global) - .SetDescription(RemoteObject::GlobalDescription); - globalScope->SetType(Scope::Type::Global()).SetObject(std::move(global)); - propertiesPair_[curObjectId_++] = Global(ecmaVm_, JSNApi::GetGlobalObject(ecmaVm_)); - return globalScope; -} - -void JSBackend::SetPauseOnException(bool flag) -{ - pauseOnException_ = flag; -} - -std::optional JSBackend::ConvertToLocal(Local &taggedValue, std::unique_ptr *result, - const CString &varValue) -{ - if (varValue == "false") { - taggedValue = JSValueRef::False(ecmaVm_); - } else if (varValue == "true") { - taggedValue = JSValueRef::True(ecmaVm_); - } else if (varValue == "undefined") { - taggedValue = JSValueRef::Undefined(ecmaVm_); - } else if (varValue[0] == '\"' && varValue[varValue.length() - 1] == '\"') { - // 2 : 2 means length - taggedValue = StringRef::NewFromUtf8(ecmaVm_, varValue.substr(1, varValue.length() - 2).c_str()); - } else { - auto begin = reinterpret_cast((varValue.c_str())); - auto end = begin + varValue.length(); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - double d = DebuggerApi::StringToDouble(begin, end, 0); - if (std::isnan(d)) { - *result = RemoteObject::FromTagged(ecmaVm_, - Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, "Unsupport expression"))); - return "Unsupported expression."; - } - taggedValue = NumberRef::New(ecmaVm_, d); - } - return {}; -} - -std::optional JSBackend::SetVregValue(int32_t regIndex, const CString &varValue, - std::unique_ptr *result) -{ - Local taggedValue; - std::optional ret = ConvertToLocal(taggedValue, result, varValue); - if (ret.has_value()) { - return ret; - } - DebuggerApi::SetVRegValue(ecmaVm_, regIndex, taggedValue); - *result = RemoteObject::FromTagged(ecmaVm_, taggedValue); - return {}; -} - -std::optional JSBackend::SetLexicalValue(int32_t level, uint32_t slot, const CString &varValue, - std::unique_ptr *result) -{ - Local taggedValue; - std::optional ret = ConvertToLocal(taggedValue, result, varValue); - if (ret.has_value()) { - return ret; - } - DebuggerApi::SetProperties(ecmaVm_, level, slot, taggedValue); - *result = RemoteObject::FromTagged(ecmaVm_, taggedValue); - return {}; -} - -std::optional JSBackend::GetVregValue(int32_t regIndex, std::unique_ptr *result) -{ - CacheObjectIfNeeded(DebuggerApi::GetVRegValue(ecmaVm_, regIndex), result); - return {}; -} - -std::optional JSBackend::GetLexicalValue(int32_t level, uint32_t slot, std::unique_ptr *result) -{ - CacheObjectIfNeeded(DebuggerApi::GetProperties(ecmaVm_, level, slot), result); - return {}; -} - -void JSBackend::GetProtoOrProtoType(const Local &value, bool isOwn, bool isAccessorOnly, - CVector> *outPropertyDesc) -{ - if (!isAccessorOnly && isOwn && !value->IsProxy()) { - return; - } - // Get Function ProtoOrDynClass - if (value->IsConstructor()) { - Local prototype = Local(value)->GetFunctionPrototype(ecmaVm_); - std::unique_ptr protoObj = std::make_unique(); - CacheObjectIfNeeded(prototype, &protoObj); - std::unique_ptr debuggerProperty = std::make_unique(); - debuggerProperty->SetName("prototype") - .SetWritable(false) - .SetConfigurable(false) - .SetEnumerable(false) - .SetIsOwn(true) - .SetValue(std::move(protoObj)); - outPropertyDesc->emplace_back(std::move(debuggerProperty)); - } - // Get __proto__ - Local proto = Local(value)->GetPrototype(ecmaVm_); - std::unique_ptr protoObj = std::make_unique(); - CacheObjectIfNeeded(proto, &protoObj); - std::unique_ptr debuggerProperty = std::make_unique(); - debuggerProperty->SetName("__proto__") - .SetWritable(true) - .SetConfigurable(true) - .SetEnumerable(false) - .SetIsOwn(true) - .SetValue(std::move(protoObj)); - outPropertyDesc->emplace_back(std::move(debuggerProperty)); -} - -void JSBackend::GetProperties(uint32_t objectId, bool isOwn, bool isAccessorOnly, - CVector> *outPropertyDesc) -{ - auto iter = propertiesPair_.find(objectId); - if (iter == propertiesPair_.end()) { - LOG(ERROR, DEBUGGER) << "JSBackend::GetProperties Unknown object id: " << objectId; - return; - } - Local value = Local(ecmaVm_, iter->second); - if (value.IsEmpty() || !value->IsObject()) { - LOG(ERROR, DEBUGGER) << "JSBackend::GetProperties should a js object"; - return; - } - Local keys = Local(value)->GetOwnPropertyNames(ecmaVm_); - uint32_t length = keys->Length(ecmaVm_); - Local name = JSValueRef::Undefined(ecmaVm_); - for (uint32_t i = 0; i < length; ++i) { - name = keys->Get(ecmaVm_, i); - PropertyAttribute jsProperty = PropertyAttribute::Default(); - if (!Local(value)->GetOwnProperty(ecmaVm_, name, jsProperty)) { - continue; - } - std::unique_ptr debuggerProperty = - PropertyDescriptor::FromProperty(ecmaVm_, name, jsProperty); - if (isAccessorOnly && !jsProperty.HasGetter() && !jsProperty.HasSetter()) { - continue; - } - if (jsProperty.HasGetter()) { - debuggerProperty->GetGet()->SetObjectId(curObjectId_); - propertiesPair_[curObjectId_++] = Global(ecmaVm_, jsProperty.GetGetter(ecmaVm_)); - } - if (jsProperty.HasSetter()) { - debuggerProperty->GetSet()->SetObjectId(curObjectId_); - propertiesPair_[curObjectId_++] = Global(ecmaVm_, jsProperty.GetSetter(ecmaVm_)); - } - if (jsProperty.HasValue()) { - Local vValue = jsProperty.GetValue(ecmaVm_); - if (vValue->IsObject() && !vValue->IsProxy()) { - debuggerProperty->GetValue()->SetObjectId(curObjectId_); - propertiesPair_[curObjectId_++] = Global(ecmaVm_, vValue); - } - } - if (name->IsSymbol()) { - debuggerProperty->GetSymbol()->SetObjectId(curObjectId_); - propertiesPair_[curObjectId_++] = Global(ecmaVm_, name); - } - outPropertyDesc->emplace_back(std::move(debuggerProperty)); - } - GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); -} - -void JSBackend::CallFunctionOn([[maybe_unused]] const CString &functionDeclaration, - std::unique_ptr *outRemoteObject) -{ - // Return EvalError temporarily. - auto error = Exception::EvalError(ecmaVm_, StringRef::NewFromUtf8(ecmaVm_, "Unsupport eval now")); - - *outRemoteObject = RemoteObject::FromTagged(ecmaVm_, error); -} - -void JSBackend::CacheObjectIfNeeded(const Local &valRef, std::unique_ptr *remoteObj) -{ - *remoteObj = RemoteObject::FromTagged(ecmaVm_, valRef); - if (valRef->IsObject() && !valRef->IsProxy()) { - (*remoteObj)->SetObjectId(curObjectId_); - propertiesPair_[curObjectId_++] = Global(ecmaVm_, valRef); - } -} - -void JSBackend::CleanUpOnPaused() -{ - curObjectId_ = 0; - propertiesPair_.clear(); - - callFrameHandlers_.clear(); - scopeObjects_.clear(); -} - -bool JSBackend::DecodeAndCheckBase64(const CString &src, CString &dest) -{ - dest.resize(base64::decoded_size(src.size())); - auto [numOctets, _] = base64::decode(dest.data(), src.data(), src.size()); - dest.resize(numOctets); - - if (numOctets > File::MAGIC_SIZE && - memcmp(dest.data(), File::MAGIC.data(), File::MAGIC_SIZE) == 0) { - return true; - } - return false; -} -} // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/agent/js_backend.h b/ecmascript/tooling/agent/js_backend.h deleted file mode 100644 index b8cb9f0f4f810217a02c2998934975f29de105bf..0000000000000000000000000000000000000000 --- a/ecmascript/tooling/agent/js_backend.h +++ /dev/null @@ -1,163 +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_AGENT_JS_BACKEND_H -#define ECMASCRIPT_TOOLING_AGENT_JS_BACKEND_H - -#include "ecmascript/tooling/agent/js_pt_hooks.h" -#include "ecmascript/tooling/base/pt_types.h" -#include "ecmascript/tooling/dispatcher.h" -#include "ecmascript/tooling/interface/js_debugger_manager.h" -#include "ecmascript/tooling/pt_js_extractor.h" -#include "libpandabase/macros.h" - -namespace panda::ecmascript::tooling { -using panda::ecmascript::CString; - -class JSBackend { -public: - explicit JSBackend(FrontEnd *frontend); - explicit JSBackend(const EcmaVM *vm); - ~JSBackend(); - - // add for hooks - void NotifyPaused(std::optional location, PauseReason reason); - void NotifyResume(); - void NotifyAllScriptParsed(); - bool NotifyScriptParsed(int32_t scriptId, const CString &fileName); - bool StepComplete(const JSPtLocation &location); - - std::optional GetPossibleBreakpoints(Location *start, Location *end, - CVector> *locations); - JSDebugger *GetDebugger() const - { - return debugger_; - } - - std::optional SetBreakpointByUrl(const CString &url, size_t lineNumber, size_t columnNumber, - const std::optional &condition, CString *outId, - CVector> *outLocations); - std::optional RemoveBreakpoint(const BreakpointDetails &metaData); - - std::optional Pause(); - std::optional Resume(); - std::optional StepInto(); - std::optional StepOver(); - std::optional StepOut(); - std::optional EvaluateValue(const CString &callFrameId, const CString &expression, - std::unique_ptr *result); - std::optional CmptEvaluateValue(const CString &callFrameId, const CString &expression, - std::unique_ptr *result); - - /** - * @brief: match first script and callback - * - * @return: true means matched and callback execute success - */ - template - bool MatchScripts(const Callback &cb, const CString &matchStr, ScriptMatchType type) const - { - for (const auto &script : scripts_) { - CString value; - switch (type) { - case ScriptMatchType::SCRIPT_ID: { - value = script.second->GetScriptId(); - break; - } - case ScriptMatchType::URL: { - value = script.second->GetUrl(); - break; - } - case ScriptMatchType::FILE_NAME: { - value = script.second->GetFileName(); - break; - } - case ScriptMatchType::HASH: { - value = script.second->GetHash(); - break; - } - default: { - return false; - } - } - if (matchStr == value) { - return cb(script.second.get()); - } - } - return false; - } - - void SetPauseOnException(bool flag); - void GetProperties(uint32_t objectId, bool isOwn, bool isAccessorOnly, - CVector> *outPropertyDesc); - void CallFunctionOn(const CString &functionDeclaration, std::unique_ptr *outRemoteObject); - // public for testcases - bool GenerateCallFrames(CVector> *callFrames); - const EcmaVM *GetEcmaVm() const - { - return ecmaVm_; - } - -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); - bool GenerateCallFrame(CallFrame *callFrame, const InterpretedFrameHandler *frameHandler, int32_t frameId); - void SaveCallFrameHandler(const InterpretedFrameHandler *frameHandler); - void GetLocalVariables(const InterpretedFrameHandler *frameHandler, const JSMethod *method, - Local &thisVal, Local &localObj); - void CacheObjectIfNeeded(const Local &valRef, std::unique_ptr *remoteObj); - void CleanUpOnPaused(); - std::unique_ptr GetLocalScopeChain(const InterpretedFrameHandler *frameHandler, - std::unique_ptr *thisObj); - void UpdateScopeObject(const InterpretedFrameHandler *frameHandler, const CString &varName, - const Local &newVal); - std::unique_ptr GetGlobalScopeChain(); - std::optional ConvertToLocal(Local &taggedValue, std::unique_ptr *result, - const CString &varValue); - std::optional SetVregValue(int32_t regIndex, const CString &varValue, - std::unique_ptr *result); - std::optional SetLexicalValue(int32_t level, uint32_t slot, const CString &varValue, - std::unique_ptr *result); - std::optional GetVregValue(int32_t regIndex, std::unique_ptr *result); - std::optional GetLexicalValue(int32_t level, uint32_t slot, std::unique_ptr *result); - void GetProtoOrProtoType(const Local &value, bool isOwn, bool isAccessorOnly, - CVector> *outPropertyDesc); - bool DecodeAndCheckBase64(const CString &src, CString &dest); - - constexpr static int32_t SPECIAL_LINE_MARK = -1; - - FrontEnd *frontend_ {nullptr}; - const EcmaVM *ecmaVm_ {nullptr}; - std::unique_ptr hooks_ {nullptr}; - JSDebugger *debugger_ {nullptr}; - CMap> extractors_ {}; - CMap> scripts_ {}; - CMap> propertiesPair_ {}; - CUnorderedMap scopeObjects_ {}; - CVector> callFrameHandlers_; - uint32_t curObjectId_ {0}; - bool pauseOnException_ {false}; - bool pauseOnNextByteCode_ {false}; - std::unique_ptr singleStepper_ {nullptr}; - JsDebuggerManager::ObjectUpdaterFunc updaterFunc_ {nullptr}; - - friend class JSPtHooks; -}; -} // namespace panda::ecmascript::tooling -#endif diff --git a/ecmascript/tooling/agent/profiler_impl.cpp b/ecmascript/tooling/agent/profiler_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..78f59f21ee85bf3f7e5e2629e4e5c0e4b40ce56d --- /dev/null +++ b/ecmascript/tooling/agent/profiler_impl.cpp @@ -0,0 +1,246 @@ +/* + * 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/tooling/agent/profiler_impl.h" + +#include "ecmascript/napi/include/dfx_jsnapi.h" +#include "ecmascript/tooling/base/pt_events.h" +#include "ecmascript/tooling/protocol_channel.h" +#include "libpandabase/utils/logger.h" + +namespace panda::ecmascript::tooling { +void ProfilerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request) +{ + static std::unordered_map dispatcherTable { + { "disable", &ProfilerImpl::DispatcherImpl::Disable }, + { "enable", &ProfilerImpl::DispatcherImpl::Enable }, + { "start", &ProfilerImpl::DispatcherImpl::Start }, + { "stop", &ProfilerImpl::DispatcherImpl::Stop }, + { "SetSamplingInterval", &ProfilerImpl::DispatcherImpl::SetSamplingInterval }, + { "getBestEffortCoverage", &ProfilerImpl::DispatcherImpl::GetBestEffortCoverage }, + { "stopPreciseCoverage", &ProfilerImpl::DispatcherImpl::StopPreciseCoverage }, + { "takePreciseCoverage", &ProfilerImpl::DispatcherImpl::TakePreciseCoverage }, + { "startPreciseCoverage", &ProfilerImpl::DispatcherImpl::StartPreciseCoverage }, + { "startTypeProfile", &ProfilerImpl::DispatcherImpl::StartTypeProfile }, + { "stopTypeProfile", &ProfilerImpl::DispatcherImpl::StopTypeProfile }, + { "takeTypeProfile", &ProfilerImpl::DispatcherImpl::TakeTypeProfile } + }; + + const std::string &method = request.GetMethod(); + LOG(DEBUG, DEBUGGER) << "dispatch [" << method << "] to ProfilerImpl"; + auto entry = dispatcherTable.find(method); + if (entry != dispatcherTable.end() && entry->second != nullptr) { + (this->*(entry->second))(request); + } else { + SendResponse(request, DispatchResponse::Fail("Unknown method: " + method)); + } +} + +void ProfilerImpl::DispatcherImpl::Disable(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->Disable(); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::Enable(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->Enable(); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::Start(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->Start(); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::Stop(const DispatchRequest &request) +{ + std::unique_ptr profile; + DispatchResponse response = profiler_->Stop(&profile); + StopReturns result(std::move(profile)); + SendResponse(request, response, result); +} + +void ProfilerImpl::DispatcherImpl::SetSamplingInterval(const DispatchRequest &request) +{ + std::unique_ptr params = SetSamplingIntervalParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + DispatchResponse response = profiler_->SetSamplingInterval(*params); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::GetBestEffortCoverage(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->GetBestEffortCoverage(); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::StopPreciseCoverage(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->StopPreciseCoverage(); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::TakePreciseCoverage(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->TakePreciseCoverage(); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::StartPreciseCoverage(const DispatchRequest &request) +{ + std::unique_ptr params = StartPreciseCoverageParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + DispatchResponse response = profiler_->StartPreciseCoverage(*params); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::StartTypeProfile(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->StartTypeProfile(); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::StopTypeProfile(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->StopTypeProfile(); + SendResponse(request, response); +} + +void ProfilerImpl::DispatcherImpl::TakeTypeProfile(const DispatchRequest &request) +{ + DispatchResponse response = profiler_->TakeTypeProfile(); + SendResponse(request, response); +} + +bool ProfilerImpl::Frontend::AllowNotify() const +{ + return channel_ != nullptr; +} + +void ProfilerImpl::Frontend::ConsoleProfileFinished() +{ + if (!AllowNotify()) { + return; + } + + tooling::ConsoleProfileFinished consoleProfileFinished; + channel_->SendNotification(consoleProfileFinished); +} + +void ProfilerImpl::Frontend::ConsoleProfileStarted() +{ + if (!AllowNotify()) { + return; + } + + tooling::ConsoleProfileStarted consoleProfileStarted; + channel_->SendNotification(consoleProfileStarted); +} + +void ProfilerImpl::Frontend::PreciseCoverageDeltaUpdate() +{ + if (!AllowNotify()) { + return; + } + + tooling::PreciseCoverageDeltaUpdate preciseCoverageDeltaUpdate; + channel_->SendNotification(preciseCoverageDeltaUpdate); +} + +DispatchResponse ProfilerImpl::Disable() +{ + LOG(ERROR, DEBUGGER) << "Disable not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::Enable() +{ + LOG(ERROR, DEBUGGER) << "Enable not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::Start() +{ + panda::DFXJSNApi::StartCpuProfilerForInfo(vm_); + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::Stop(std::unique_ptr *profile) +{ + auto profileInfo = panda::DFXJSNApi::StopCpuProfilerForInfo(); + if (profileInfo == nullptr) { + LOG(ERROR, DEBUGGER) << "Transfer DFXJSNApi::StopCpuProfilerImpl is failure"; + return DispatchResponse::Fail("Stop is failure"); + } + *profile = Profile::FromProfileInfo(*profileInfo); + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::SetSamplingInterval(const SetSamplingIntervalParams ¶ms) +{ + panda::DFXJSNApi::SetCpuSamplingInterval(params.GetInterval()); + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::GetBestEffortCoverage() +{ + LOG(ERROR, DEBUGGER) << "GetBestEffortCoverage not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::StopPreciseCoverage() +{ + LOG(ERROR, DEBUGGER) << "StopPreciseCoverage not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::TakePreciseCoverage() +{ + LOG(ERROR, DEBUGGER) << "TakePreciseCoverage not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::StartPreciseCoverage([[maybe_unused]] const StartPreciseCoverageParams ¶ms) +{ + LOG(ERROR, DEBUGGER) << "StartPreciseCoverage not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::StartTypeProfile() +{ + LOG(ERROR, DEBUGGER) << "StartTypeProfile not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::StopTypeProfile() +{ + LOG(ERROR, DEBUGGER) << "StopTypeProfile not support now."; + return DispatchResponse::Ok(); +} + +DispatchResponse ProfilerImpl::TakeTypeProfile() +{ + LOG(ERROR, DEBUGGER) << "TakeTypeProfile not support now."; + return DispatchResponse::Ok(); +} +} // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/agent/profiler_impl.h b/ecmascript/tooling/agent/profiler_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..47f9a5ea5a679916d217ea7def6455d1fb787255 --- /dev/null +++ b/ecmascript/tooling/agent/profiler_impl.h @@ -0,0 +1,94 @@ +/* + * 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_AGENT_PROFILER_IMPL_H +#define ECMASCRIPT_TOOLING_AGENT_PROFILER_IMPL_H + +#include "ecmascript/dfx/cpu_profiler/samples_record.h" +#include "ecmascript/tooling/base/pt_params.h" +#include "ecmascript/tooling/base/pt_returns.h" +#include "ecmascript/tooling/dispatcher.h" +#include "libpandabase/macros.h" + +namespace panda::ecmascript::tooling { +class ProfilerImpl final { +public: + ProfilerImpl(const EcmaVM *vm, ProtocolChannel *channel) : vm_(vm), frontend_(channel) {} + ~ProfilerImpl() = default; + + DispatchResponse Disable(); + DispatchResponse Enable(); + DispatchResponse Start(); + DispatchResponse Stop(std::unique_ptr *profile); + DispatchResponse SetSamplingInterval(const SetSamplingIntervalParams ¶ms); + DispatchResponse GetBestEffortCoverage(); + DispatchResponse StopPreciseCoverage(); + DispatchResponse TakePreciseCoverage(); + DispatchResponse StartPreciseCoverage (const StartPreciseCoverageParams ¶ms); + DispatchResponse StartTypeProfile(); + DispatchResponse StopTypeProfile(); + DispatchResponse TakeTypeProfile(); + + class DispatcherImpl final : public DispatcherBase { + public: + DispatcherImpl(ProtocolChannel *channel, std::unique_ptr profiler) + : DispatcherBase(channel), profiler_(std::move(profiler)) {} + ~DispatcherImpl() override = default; + + void Dispatch(const DispatchRequest &request) override; + void Enable(const DispatchRequest &request); + void Disable(const DispatchRequest &request); + void Start(const DispatchRequest &request); + void Stop(const DispatchRequest &request); + void SetSamplingInterval(const DispatchRequest &request); + void GetBestEffortCoverage(const DispatchRequest &request); + void StopPreciseCoverage(const DispatchRequest &request); + void TakePreciseCoverage(const DispatchRequest &request); + void StartPreciseCoverage(const DispatchRequest &request); + void StartTypeProfile(const DispatchRequest &request); + void StopTypeProfile(const DispatchRequest &request); + void TakeTypeProfile(const DispatchRequest &request); + + private: + NO_COPY_SEMANTIC(DispatcherImpl); + NO_MOVE_SEMANTIC(DispatcherImpl); + + using AgentHandler = void (ProfilerImpl::DispatcherImpl::*)(const DispatchRequest &request); + std::unique_ptr profiler_ {}; + }; + + class Frontend { + public: + explicit Frontend(ProtocolChannel *channel) : channel_(channel) {} + + void ConsoleProfileFinished(); + void ConsoleProfileStarted(); + void PreciseCoverageDeltaUpdate(); + + private: + bool AllowNotify() const; + + ProtocolChannel *channel_ {nullptr}; + }; + +private: + NO_COPY_SEMANTIC(ProfilerImpl); + NO_MOVE_SEMANTIC(ProfilerImpl); + + const EcmaVM *vm_ {nullptr}; + [[maybe_unused]] Frontend frontend_; +}; +} // namespace panda::ecmascript::tooling +#endif diff --git a/ecmascript/tooling/agent/runtime_impl.cpp b/ecmascript/tooling/agent/runtime_impl.cpp index 8c2b6f752ab75eaa7382fa4a2ee2f940ba4393f0..75406f68cc4fbcd1a4d1e23b30845309f1a12893 100644 --- a/ecmascript/tooling/agent/runtime_impl.cpp +++ b/ecmascript/tooling/agent/runtime_impl.cpp @@ -15,120 +15,340 @@ #include "ecmascript/tooling/agent/runtime_impl.h" +#include + +#include "ecmascript/napi/include/dfx_jsnapi.h" #include "ecmascript/tooling/base/pt_returns.h" +#include "ecmascript/tooling/protocol_channel.h" #include "libpandabase/utils/logger.h" namespace panda::ecmascript::tooling { -RuntimeImpl::DispatcherImpl::DispatcherImpl(FrontEnd *frontend, std::unique_ptr runtime) - : DispatcherBase(frontend), runtime_(std::move(runtime)) -{ - dispatcherTable_["enable"] = &RuntimeImpl::DispatcherImpl::Enable; - dispatcherTable_["getProperties"] = &RuntimeImpl::DispatcherImpl::GetProperties; - dispatcherTable_["runIfWaitingForDebugger"] = &RuntimeImpl::DispatcherImpl::RunIfWaitingForDebugger; - dispatcherTable_["callFunctionOn"] = &RuntimeImpl::DispatcherImpl::CallFunctionOn; -} - void RuntimeImpl::DispatcherImpl::Dispatch(const DispatchRequest &request) { - CString method = request.GetMethod(); + static std::unordered_map dispatcherTable { + { "enable", &RuntimeImpl::DispatcherImpl::Enable }, + { "getProperties", &RuntimeImpl::DispatcherImpl::GetProperties }, + { "runIfWaitingForDebugger", &RuntimeImpl::DispatcherImpl::RunIfWaitingForDebugger }, + { "callFunctionOn", &RuntimeImpl::DispatcherImpl::CallFunctionOn }, + { "getHeapUsage", &RuntimeImpl::DispatcherImpl::GetHeapUsage } + }; + + const std::string &method = request.GetMethod(); LOG(DEBUG, DEBUGGER) << "dispatch [" << method << "] to RuntimeImpl"; - auto entry = dispatcherTable_.find(method); - if (entry != dispatcherTable_.end()) { + auto entry = dispatcherTable.find(method); + if (entry != dispatcherTable.end()) { (this->*(entry->second))(request); } else { LOG(ERROR, DEBUGGER) << "unknown method: " << method; - SendResponse(request, DispatchResponse::Fail("unknown method: " + method), nullptr); + SendResponse(request, DispatchResponse::Fail("unknown method: " + method)); } } void RuntimeImpl::DispatcherImpl::Enable(const DispatchRequest &request) { DispatchResponse response = runtime_->Enable(); - SendResponse(request, response, nullptr); + SendResponse(request, response); +} + +void RuntimeImpl::DispatcherImpl::Disable(const DispatchRequest &request) +{ + DispatchResponse response = runtime_->Disable(); + SendResponse(request, response); } void RuntimeImpl::DispatcherImpl::RunIfWaitingForDebugger(const DispatchRequest &request) { DispatchResponse response = runtime_->RunIfWaitingForDebugger(); - SendResponse(request, response, nullptr); + SendResponse(request, response); } void RuntimeImpl::DispatcherImpl::GetProperties(const DispatchRequest &request) { - std::unique_ptr params = GetPropertiesParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = GetPropertiesParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } - CVector> outPropertyDesc; - std::optional>> outInternalDescs; - std::optional>> outPrivateProperties; + std::vector> outPropertyDesc; + std::optional>> outInternalDescs; + std::optional>> outPrivateProperties; std::optional> outExceptionDetails; - DispatchResponse response = runtime_->GetProperties(std::move(params), &outPropertyDesc, &outInternalDescs, + DispatchResponse response = runtime_->GetProperties(*params, &outPropertyDesc, &outInternalDescs, &outPrivateProperties, &outExceptionDetails); if (outExceptionDetails) { LOG(WARNING, DEBUGGER) << "GetProperties thrown an exception"; } - std::unique_ptr result = std::make_unique(std::move(outPropertyDesc), + GetPropertiesReturns result(std::move(outPropertyDesc), std::move(outInternalDescs), std::move(outPrivateProperties), std::move(outExceptionDetails)); - SendResponse(request, response, std::move(result)); + SendResponse(request, response, result); } void RuntimeImpl::DispatcherImpl::CallFunctionOn(const DispatchRequest &request) { - std::unique_ptr params = - CallFunctionOnParams::Create(request.GetEcmaVM(), request.GetParams()); + std::unique_ptr params = CallFunctionOnParams::Create(request.GetParams()); if (params == nullptr) { - SendResponse(request, DispatchResponse::Fail("Debugger got wrong params"), nullptr); + SendResponse(request, DispatchResponse::Fail("wrong params")); return; } std::unique_ptr outRemoteObject; std::optional> outExceptionDetails; - DispatchResponse response = runtime_->CallFunctionOn(std::move(params), &outRemoteObject, &outExceptionDetails); + DispatchResponse response = runtime_->CallFunctionOn(*params, &outRemoteObject, &outExceptionDetails); if (outExceptionDetails) { LOG(WARNING, DEBUGGER) << "CallFunctionOn thrown an exception"; } - std::unique_ptr result = std::make_unique(std::move(outRemoteObject), - std::move(outExceptionDetails)); - SendResponse(request, response, std::move(result)); + CallFunctionOnReturns result(std::move(outRemoteObject), std::move(outExceptionDetails)); + SendResponse(request, response, result); +} + +void RuntimeImpl::DispatcherImpl::GetHeapUsage(const DispatchRequest &request) +{ + double usedSize = 0; + double totalSize = 0; + DispatchResponse response = runtime_->GetHeapUsage(&usedSize, &totalSize); + GetHeapUsageReturns result(usedSize, totalSize); + SendResponse(request, response, result); +} + +bool RuntimeImpl::Frontend::AllowNotify() const +{ + return channel_ != nullptr; +} + +void RuntimeImpl::Frontend::RunIfWaitingForDebugger() +{ + if (!AllowNotify()) { + return; + } + + channel_->RunIfWaitingForDebugger(); } DispatchResponse RuntimeImpl::Enable() { - auto ecmaVm = const_cast(backend_->GetEcmaVm()); - ecmaVm->GetJsDebuggerManager()->SetDebugMode(true); - backend_->NotifyAllScriptParsed(); + return DispatchResponse::Ok(); +} + +DispatchResponse RuntimeImpl::Disable() +{ return DispatchResponse::Ok(); } DispatchResponse RuntimeImpl::RunIfWaitingForDebugger() { - return DispatchResponse::Create(backend_->Resume()); + frontend_.RunIfWaitingForDebugger(); + return DispatchResponse::Ok(); } -DispatchResponse RuntimeImpl::GetProperties(std::unique_ptr params, - CVector> *outPropertyDesc, - [[maybe_unused]] std::optional>> *outInternalDescs, - [[maybe_unused]] std::optional>> *outPrivateProps, +DispatchResponse RuntimeImpl::CallFunctionOn([[maybe_unused]] const CallFunctionOnParams ¶ms, + std::unique_ptr *outRemoteObject, [[maybe_unused]] std::optional> *outExceptionDetails) { - backend_->GetProperties(DebuggerApi::CStringToULL(params->GetObjectId()), - params->GetOwnProperties(), - params->GetAccessPropertiesOnly(), - outPropertyDesc); + // Return EvalError temporarily. + auto error = Exception::EvalError(vm_, StringRef::NewFromUtf8(vm_, "Unsupport eval now")); + *outRemoteObject = RemoteObject::FromTagged(vm_, error); return DispatchResponse::Ok(); } -DispatchResponse RuntimeImpl::CallFunctionOn(std::unique_ptr params, - std::unique_ptr *outRemoteObject, +DispatchResponse RuntimeImpl::GetHeapUsage(double *usedSize, double *totalSize) +{ + *totalSize = static_cast(DFXJSNApi::GetHeapTotalSize(vm_)); + *usedSize = static_cast(DFXJSNApi::GetHeapUsedSize(vm_)); + return DispatchResponse::Ok(); +} + +DispatchResponse RuntimeImpl::GetProperties(const GetPropertiesParams ¶ms, + std::vector> *outPropertyDesc, + [[maybe_unused]] std::optional>> *outInternalDescs, + [[maybe_unused]] std::optional>> *outPrivateProps, [[maybe_unused]] std::optional> *outExceptionDetails) { - backend_->CallFunctionOn(params->GetFunctionDeclaration(), outRemoteObject); + RemoteObjectId objectId = params.GetObjectId(); + bool isOwn = params.GetOwnProperties(); + bool isAccessorOnly = params.GetAccessPropertiesOnly(); + auto iter = properties_.find(objectId); + if (iter == properties_.end()) { + LOG(ERROR, DEBUGGER) << "RuntimeImpl::GetProperties Unknown object id: " << objectId; + return DispatchResponse::Fail("Unknown object id"); + } + Local value = Local(vm_, iter->second); + if (value.IsEmpty() || !value->IsObject()) { + LOG(ERROR, DEBUGGER) << "RuntimeImpl::GetProperties should a js object"; + return DispatchResponse::Fail("Not a object"); + } + if (value->IsArrayBuffer()) { + Local arrayBufferRef(value); + AddTypedArrayRefs(arrayBufferRef, outPropertyDesc); + } + Local keys = Local(value)->GetOwnPropertyNames(vm_); + int32_t length = keys->Length(vm_); + Local name = JSValueRef::Undefined(vm_); + for (int32_t i = 0; i < length; ++i) { + name = keys->Get(vm_, i); + PropertyAttribute jsProperty = PropertyAttribute::Default(); + if (!Local(value)->GetOwnProperty(vm_, name, jsProperty)) { + continue; + } + std::unique_ptr debuggerProperty = + PropertyDescriptor::FromProperty(vm_, name, jsProperty); + if (isAccessorOnly && !jsProperty.HasGetter() && !jsProperty.HasSetter()) { + continue; + } + if (debuggerProperty->HasGet()) { + debuggerProperty->GetGet()->SetObjectId(curObjectId_); + properties_[curObjectId_++] = Global(vm_, jsProperty.GetGetter(vm_)); + } + if (debuggerProperty->HasSet()) { + debuggerProperty->GetSet()->SetObjectId(curObjectId_); + properties_[curObjectId_++] = Global(vm_, jsProperty.GetSetter(vm_)); + } + if (debuggerProperty->HasValue()) { + Local vValue = jsProperty.GetValue(vm_); + if (vValue->IsObject() && !vValue->IsProxy()) { + debuggerProperty->GetValue()->SetObjectId(curObjectId_); + properties_[curObjectId_++] = Global(vm_, vValue); + } + } + if (debuggerProperty->HasSymbol()) { + debuggerProperty->GetSymbol()->SetObjectId(curObjectId_); + properties_[curObjectId_++] = Global(vm_, name); + } + outPropertyDesc->emplace_back(std::move(debuggerProperty)); + } + GetProtoOrProtoType(value, isOwn, isAccessorOnly, outPropertyDesc); + GetAdditionalProperties(value, outPropertyDesc); + return DispatchResponse::Ok(); } -} // namespace panda::ecmascript::tooling + +void RuntimeImpl::AddTypedArrayRefs(Local arrayBufferRef, + std::vector> *outPropertyDesc) +{ + int32_t arrayBufferByteLength = arrayBufferRef->ByteLength(vm_); + int32_t typedArrayLength = arrayBufferByteLength; + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int8Array]]", outPropertyDesc); + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint8Array]]", outPropertyDesc); + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint8ClampedArray]]", outPropertyDesc); + + if ((arrayBufferByteLength % NumberSize::BYTES_OF_16BITS) == 0) { + typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_16BITS; + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int16Array]]", outPropertyDesc); + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint16Array]]", outPropertyDesc); + } + + if ((arrayBufferByteLength % NumberSize::BYTES_OF_32BITS) == 0) { + typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_32BITS; + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Int32Array]]", outPropertyDesc); + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Uint32Array]]", outPropertyDesc); + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Float32Array]]", outPropertyDesc); + } + + if ((arrayBufferByteLength % NumberSize::BYTES_OF_64BITS) == 0) { + typedArrayLength = arrayBufferByteLength / NumberSize::BYTES_OF_64BITS; + AddTypedArrayRef(arrayBufferRef, typedArrayLength, "[[Float64Array]]", outPropertyDesc); + } +} + +template +void RuntimeImpl::AddTypedArrayRef(Local arrayBufferRef, int32_t length, const char* name, + std::vector> *outPropertyDesc) +{ + Local jsValueRefTypedArray(TypedArrayRef::New(vm_, arrayBufferRef, 0, length)); + std::unique_ptr remoteObjectTypedArray = RemoteObject::FromTagged(vm_, jsValueRefTypedArray); + remoteObjectTypedArray->SetObjectId(curObjectId_); + properties_[curObjectId_++] = Global(vm_, jsValueRefTypedArray); + std::unique_ptr debuggerProperty = std::make_unique(); + debuggerProperty->SetName(name) + .SetWritable(true) + .SetConfigurable(true) + .SetEnumerable(false) + .SetIsOwn(true) + .SetValue(std::move(remoteObjectTypedArray)); + outPropertyDesc->emplace_back(std::move(debuggerProperty)); +} + +void RuntimeImpl::CacheObjectIfNeeded(Local valRef, RemoteObject *remoteObj) +{ + if (valRef->IsObject() && !valRef->IsProxy()) { + remoteObj->SetObjectId(curObjectId_); + properties_[curObjectId_++] = Global(vm_, valRef); + } +} + +void RuntimeImpl::GetProtoOrProtoType(Local value, bool isOwn, bool isAccessorOnly, + std::vector> *outPropertyDesc) +{ + if (!isAccessorOnly && isOwn && !value->IsProxy()) { + return; + } + // Get Function ProtoOrDynClass + if (value->IsConstructor()) { + Local prototype = Local(value)->GetFunctionPrototype(vm_); + std::unique_ptr protoObj = RemoteObject::FromTagged(vm_, prototype); + CacheObjectIfNeeded(prototype, protoObj.get()); + std::unique_ptr debuggerProperty = std::make_unique(); + debuggerProperty->SetName("prototype") + .SetWritable(false) + .SetConfigurable(false) + .SetEnumerable(false) + .SetIsOwn(true) + .SetValue(std::move(protoObj)); + outPropertyDesc->emplace_back(std::move(debuggerProperty)); + } + // Get __proto__ + Local proto = Local(value)->GetPrototype(vm_); + std::unique_ptr protoObj = RemoteObject::FromTagged(vm_, proto); + CacheObjectIfNeeded(proto, protoObj.get()); + std::unique_ptr debuggerProperty = std::make_unique(); + debuggerProperty->SetName("__proto__") + .SetWritable(true) + .SetConfigurable(true) + .SetEnumerable(false) + .SetIsOwn(true) + .SetValue(std::move(protoObj)); + outPropertyDesc->emplace_back(std::move(debuggerProperty)); +} + +void RuntimeImpl::GetAdditionalProperties(Local value, + std::vector> *outPropertyDesc) +{ + // The length of the TypedArray have to be limited(less than or equal to lengthTypedArrayLimit) until we construct + // the PropertyPreview class. Let lengthTypedArrayLimit be 10000 temporarily. + static const uint32_t lengthTypedArrayLimit = 10000; + + // The width of the string-expression for JSTypedArray::MAX_TYPED_ARRAY_INDEX which is euqal to + // JSObject::MAX_ELEMENT_INDEX which is equal to std::numeric_limits::max(). (42,9496,7295) + static const int32_t widthStrExprMaxElementIndex = 10; + + if (value->IsTypedArray()) { + Local localTypedArrayRef(value); + uint32_t lengthTypedArray = localTypedArrayRef->ArrayLength(vm_); + if (lengthTypedArray > lengthTypedArrayLimit) { + LOG(ERROR, DEBUGGER) << "The length of the TypedArray is non-compliant or unsupported."; + return; + } + for (uint32_t i = 0; i < lengthTypedArray; i++) { + Local localValRefElement = localTypedArrayRef->Get(vm_, i); + std::unique_ptr remoteObjElement = RemoteObject::FromTagged(vm_, localValRefElement); + remoteObjElement->SetObjectId(curObjectId_); + properties_[curObjectId_++] = Global(vm_, localValRefElement); + std::unique_ptr debuggerProperty = std::make_unique(); + + std::ostringstream osNameElement; + osNameElement << std::right << std::setw(widthStrExprMaxElementIndex) << i; + std::string cStrNameElement = osNameElement.str(); + debuggerProperty->SetName(cStrNameElement) + .SetWritable(true) + .SetConfigurable(true) + .SetEnumerable(false) + .SetIsOwn(true) + .SetValue(std::move(remoteObjElement)); + outPropertyDesc->emplace_back(std::move(debuggerProperty)); + } + } +} +} // namespace panda::ecmascript::tooling \ No newline at end of file diff --git a/ecmascript/tooling/agent/runtime_impl.h b/ecmascript/tooling/agent/runtime_impl.h index 2b408481c1b29e0f31b7651ab7d5ba78898203ed..34e7ec26d25b5c904801ec239e158b80efd27cb2 100644 --- a/ecmascript/tooling/agent/runtime_impl.h +++ b/ecmascript/tooling/agent/runtime_impl.h @@ -17,45 +17,47 @@ #define ECMASCRIPT_TOOLING_AGENT_RUNTIME_IMPL_H #include "libpandabase/macros.h" -#include "ecmascript/tooling/agent/js_backend.h" #include "ecmascript/tooling/base/pt_params.h" #include "ecmascript/tooling/dispatcher.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::CString; - class RuntimeImpl final { public: - explicit RuntimeImpl(JSBackend *backend) : backend_(backend) {} + RuntimeImpl(const EcmaVM *vm, ProtocolChannel *channel) + : vm_(vm), frontend_(channel) {} ~RuntimeImpl() = default; DispatchResponse Enable(); + DispatchResponse Disable(); DispatchResponse RunIfWaitingForDebugger(); - DispatchResponse GetProperties( - std::unique_ptr params, - CVector> *outPropertyDesc, - std::optional>> *outInternalDescs, - std::optional>> *outPrivateProps, - std::optional> *outExceptionDetails); DispatchResponse CallFunctionOn( - std::unique_ptr params, + const CallFunctionOnParams ¶ms, std::unique_ptr *outRemoteObject, std::optional> *outExceptionDetails); + DispatchResponse GetHeapUsage(double *usedSize, double *totalSize); + DispatchResponse GetProperties( + const GetPropertiesParams ¶ms, + std::vector> *outPropertyDesc, + std::optional>> *outInternalDescs, + std::optional>> *outPrivateProps, + std::optional> *outExceptionDetails); class DispatcherImpl final : public DispatcherBase { public: - DispatcherImpl(FrontEnd *frontend, std::unique_ptr runtime); + DispatcherImpl(ProtocolChannel *channel, std::unique_ptr runtime) + : DispatcherBase(channel), runtime_(std::move(runtime)) {} ~DispatcherImpl() override = default; void Dispatch(const DispatchRequest &request) override; + void Disable(const DispatchRequest &request); void Enable(const DispatchRequest &request); void RunIfWaitingForDebugger(const DispatchRequest &request); void GetProperties(const DispatchRequest &request); void CallFunctionOn(const DispatchRequest &request); - + void GetHeapUsage(const DispatchRequest &request); + private: using AgentHandler = void (RuntimeImpl::DispatcherImpl::*)(const DispatchRequest &request); - CMap dispatcherTable_ {}; std::unique_ptr runtime_ {}; NO_COPY_SEMANTIC(DispatcherImpl); @@ -65,8 +67,39 @@ public: private: NO_COPY_SEMANTIC(RuntimeImpl); NO_MOVE_SEMANTIC(RuntimeImpl); + enum NumberSize : uint8_t { BYTES_OF_16BITS = 2, BYTES_OF_32BITS = 4, BYTES_OF_64BITS = 8 }; + + void CacheObjectIfNeeded(Local valRef, RemoteObject *remoteObj); + + template + void AddTypedArrayRef(Local arrayBufferRef, int32_t length, + const char* name, std::vector> *outPropertyDesc); + void AddTypedArrayRefs(Local arrayBufferRef, + std::vector> *outPropertyDesc); + void GetProtoOrProtoType(Local value, bool isOwn, bool isAccessorOnly, + std::vector> *outPropertyDesc); + void GetAdditionalProperties(Local value, + std::vector> *outPropertyDesc); + + class Frontend { + public: + explicit Frontend(ProtocolChannel *channel) : channel_(channel) {} + + void RunIfWaitingForDebugger(); + + private: + bool AllowNotify() const; + + ProtocolChannel *channel_ {nullptr}; + }; + + const EcmaVM *vm_ {nullptr}; + Frontend frontend_; + + RemoteObjectId curObjectId_ {0}; + std::unordered_map> properties_ {}; - JSBackend *backend_{nullptr}; + friend class DebuggerImpl; }; } // namespace panda::ecmascript::tooling #endif \ No newline at end of file diff --git a/ecmascript/tooling/interface/debugger_api.cpp b/ecmascript/tooling/backend/debugger_api.cpp similarity index 55% rename from ecmascript/tooling/interface/debugger_api.cpp rename to ecmascript/tooling/backend/debugger_api.cpp index a0b804136f2087b98b4f1910aa7935b090ce1250..62ae3c1683557c8b2b49a750571272015e803f2b 100644 --- a/ecmascript/tooling/interface/debugger_api.cpp +++ b/ecmascript/tooling/backend/debugger_api.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,18 +13,18 @@ * limitations under the License. */ -#include "ecmascript/tooling/interface/debugger_api.h" +#include "ecmascript/tooling/backend/debugger_api.h" #include "ecmascript/base/number_helper.h" -#include "ecmascript/class_linker/program_object-inl.h" #include "ecmascript/interpreter/frame_handler.h" +#include "ecmascript/interpreter/slow_runtime_stub.h" +#include "ecmascript/interpreter/fast_runtime_stub-inl.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_method.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/mem/c_string.h" #include "ecmascript/napi/jsnapi_helper-inl.h" -#include "ecmascript/tooling/interface/js_debugger.h" -#include "ecmascript/tooling/interface/js_debugger_manager.h" +#include "ecmascript/tooling/backend/js_debugger.h" namespace panda::ecmascript::tooling { using panda::ecmascript::base::ALLOW_BINARY; @@ -32,22 +32,6 @@ using panda::ecmascript::base::ALLOW_HEX; using panda::ecmascript::base::ALLOW_OCTAL; using panda::ecmascript::base::NumberHelper; -// CString -uint64_t DebuggerApi::CStringToULL(const CString &str) -{ - return panda::ecmascript::CStringToULL(str); -} - -CString DebuggerApi::ToCString(int32_t number) -{ - return panda::ecmascript::ToCString(number); -} - -CString DebuggerApi::ConvertToString(const std::string &str) -{ - return panda::ecmascript::ConvertToString(str); -} - // InterpretedFrameHandler uint32_t DebuggerApi::GetStackDepth(const EcmaVM *ecmaVm) { @@ -96,41 +80,9 @@ JSMethod *DebuggerApi::GetMethod(const EcmaVM *ecmaVm) return InterpretedFrameHandler(ecmaVm->GetJSThread()).GetMethod(); } -void DebuggerApi::SetClosureVariables(const EcmaVM *ecmaVm, const InterpretedFrameHandler *frameHandler, - Local &localObj) -{ - JSTaggedValue env = DebuggerApi::GetEnv(frameHandler); - if (env.IsTaggedArray() && DebuggerApi::GetBytecodeOffset(frameHandler) != 0) { - LexicalEnv *lexEnv = LexicalEnv::Cast(env.GetTaggedObject()); - if (lexEnv->GetScopeInfo().IsHole()) { - return; - } - auto ptr = JSNativePointer::Cast(lexEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer(); - auto *scopeDebugInfo = reinterpret_cast(ptr); - JSThread *thread = ecmaVm->GetJSThread(); - for (const auto &scopeInfo : scopeDebugInfo->scopeInfo) { - if (scopeInfo.name == "this" || scopeInfo.name == "4newTarget") { - continue; - } - Local name = StringRef::NewFromUtf8(ecmaVm, scopeInfo.name.c_str()); - Local value = JSNApiHelper::ToLocal( - JSHandle(thread, lexEnv->GetProperties(scopeInfo.slot))); - PropertyAttribute descriptor(value, true, true, true); - localObj->DefineProperty(ecmaVm, name, descriptor); - } - } -} - -Local DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm, size_t index) +void DebuggerApi::SetVRegValue(InterpretedFrameHandler *frameHandler, size_t index, Local value) { - auto value = InterpretedFrameHandler(ecmaVm->GetJSThread()).GetVRegValue(index); - JSHandle handledValue(ecmaVm->GetJSThread(), value); - return JSNApiHelper::ToLocal(handledValue); -} - -void DebuggerApi::SetVRegValue(const EcmaVM *ecmaVm, size_t index, Local value) -{ - return InterpretedFrameHandler(ecmaVm->GetJSThread()).SetVRegValue(index, JSNApiHelper::ToJSTaggedValue(*value)); + return frameHandler->SetVRegValue(index, JSNApiHelper::ToJSTaggedValue(*value)); } uint32_t DebuggerApi::GetBytecodeOffset(const InterpretedFrameHandler *frameHandler) @@ -153,6 +105,26 @@ JSTaggedType *DebuggerApi::GetSp(const InterpretedFrameHandler *frameHandler) return frameHandler->GetSp(); } +int32_t DebuggerApi::GetVregIndex(const InterpretedFrameHandler *frameHandler, std::string_view name) +{ + JSMethod *method = frameHandler->GetMethod(); + if (method->IsNativeWithCallField()) { + LOG(ERROR, DEBUGGER) << "GetVregIndex: native frame not support"; + return -1; + } + JSPtExtractor *extractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(method->GetJSPandaFile()); + if (extractor == nullptr) { + LOG(ERROR, DEBUGGER) << "GetVregIndex: extractor is null"; + return -1; + } + auto table = extractor->GetLocalVariableTable(method->GetMethodId()); + auto iter = table.find(name.data()); + if (iter == table.end()) { + return -1; + } + return iter->second; +} + Local DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm, const InterpretedFrameHandler *frameHandler, size_t index) { @@ -180,22 +152,6 @@ void DebuggerApi::ClearException(const EcmaVM *ecmaVm) return ecmaVm->GetJSThread()->ClearException(); } -// EcmaVM -const panda_file::File *DebuggerApi::FindPandaFile(const EcmaVM *ecmaVm, const CString &fileName) -{ - const panda_file::File *pfs = nullptr; - EcmaVM::GetJSPandaFileManager()->EnumerateJSPandaFiles([&pfs, fileName]( - const panda::ecmascript::JSPandaFile *jsPandaFile) { - if (jsPandaFile->GetJSPandaFileDesc() == fileName) { - pfs = jsPandaFile->GetPandaFile(); - return false; - } - return true; - }); - - return pfs; -} - // NumberHelper double DebuggerApi::StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix) { @@ -219,7 +175,7 @@ void DebuggerApi::RegisterHooks(JSDebugger *debugger, PtHooks *hooks) } bool DebuggerApi::SetBreakpoint(JSDebugger *debugger, const JSPtLocation &location, - const Local &condFuncRef) + Local condFuncRef) { return debugger->SetBreakpoint(location, condFuncRef); } @@ -230,40 +186,44 @@ bool DebuggerApi::RemoveBreakpoint(JSDebugger *debugger, const JSPtLocation &loc } // JSMethod -CString DebuggerApi::ParseFunctionName(const JSMethod *method) +std::string DebuggerApi::ParseFunctionName(const JSMethod *method) { return method->ParseFunctionName(); } // ScopeInfo -Local DebuggerApi::GetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t slot) +Local DebuggerApi::GetProperties(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + int32_t level, uint32_t slot) { - JSTaggedValue env = GetCurrentEvaluateEnv(ecmaVm); + JSTaggedValue env = frameHandler->GetEnv(); for (int i = 0; i < level; i++) { JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); ASSERT(!taggedParentEnv.IsUndefined()); env = taggedParentEnv; } JSTaggedValue value = LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot); - JSHandle handledValue(ecmaVm->GetJSThread(), value); + JSHandle handledValue(vm->GetJSThread(), value); return JSNApiHelper::ToLocal(handledValue); } -void DebuggerApi::SetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t slot, Local value) +void DebuggerApi::SetProperties(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + int32_t level, uint32_t slot, Local value) { - JSTaggedValue env = GetCurrentEvaluateEnv(ecmaVm); + JSTaggedValue env = frameHandler->GetEnv(); for (int i = 0; i < level; i++) { JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); ASSERT(!taggedParentEnv.IsUndefined()); env = taggedParentEnv; } JSTaggedValue target = JSNApiHelper::ToJSHandle(value).GetTaggedValue(); - LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(ecmaVm->GetJSThread(), slot, target); + LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(vm->GetJSThread(), slot, target); } -bool DebuggerApi::EvaluateLexicalValue(const EcmaVM *ecmaVm, const CString &name, int32_t &level, uint32_t &slot) +std::pair DebuggerApi::GetLevelSlot(const InterpretedFrameHandler *frameHandler, + std::string_view name) { - JSTaggedValue curEnv = GetCurrentEvaluateEnv(ecmaVm); + int32_t level = 0; + JSTaggedValue curEnv = frameHandler->GetEnv(); for (; curEnv.IsTaggedArray(); curEnv = LexicalEnv::Cast(curEnv.GetTaggedObject())->GetParentEnv(), level++) { LexicalEnv *lexicalEnv = LexicalEnv::Cast(curEnv.GetTaggedObject()); if (lexicalEnv->GetScopeInfo().IsHole()) { @@ -272,84 +232,87 @@ bool DebuggerApi::EvaluateLexicalValue(const EcmaVM *ecmaVm, const CString &name auto result = JSNativePointer::Cast(lexicalEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer(); ScopeDebugInfo *scopeDebugInfo = reinterpret_cast(result); for (const auto &info : scopeDebugInfo->scopeInfo) { - if (info.name == name) { - slot = info.slot; - return true; + if (info.name == name.data()) { + return std::make_pair(level, info.slot); } } } - return false; + return std::make_pair(-1, 0); } -Local DebuggerApi::GetLexicalValueInfo(const EcmaVM *ecmaVm, const CString &name) +Local DebuggerApi::GetGlobalValue(const EcmaVM *vm, Local name) { - JSThread *thread = ecmaVm->GetJSThread(); - JSTaggedValue curEnv = thread->GetCurrentLexenv(); - for (; curEnv.IsTaggedArray(); curEnv = LexicalEnv::Cast(curEnv.GetTaggedObject())->GetParentEnv()) { - LexicalEnv *lexicalEnv = LexicalEnv::Cast(curEnv.GetTaggedObject()); - if (lexicalEnv->GetScopeInfo().IsHole()) { - continue; - } - void *pointer = JSNativePointer::Cast(lexicalEnv->GetScopeInfo().GetTaggedObject())->GetExternalPointer(); - ScopeDebugInfo *scopeDebugInfo = static_cast(pointer); - for (const auto &info : scopeDebugInfo->scopeInfo) { - if (info.name == name) { - uint16_t slot = info.slot; - JSTaggedValue value = lexicalEnv->GetProperties(slot); - JSHandle handledValue(thread, value); - return JSNApiHelper::ToLocal(handledValue); - } - } + JSTaggedValue result; + JSTaggedValue globalObj = vm->GetGlobalEnv()->GetGlobalObject(); + JSThread *thread = vm->GetJSThread(); + + JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name); + JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key); + if (!globalRec.IsUndefined()) { + ASSERT(globalRec.IsPropertyBox()); + result = PropertyBox::Cast(globalRec.GetTaggedObject())->GetValue(); + return JSNApiHelper::ToLocal(JSHandle(thread, result)); } - JSHandle handledValue(thread, JSTaggedValue::Hole()); - return JSNApiHelper::ToLocal(handledValue); + + JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key); + if (!globalVar.IsHole()) { + return JSNApiHelper::ToLocal(JSHandle(thread, globalVar)); + } else { + result = SlowRuntimeStub::TryLdGlobalByName(thread, globalObj, key); + return JSNApiHelper::ToLocal(JSHandle(thread, result)); + } + + return JSValueRef::Exception(vm); } -void DebuggerApi::InitJSDebugger(JSDebugger *debugger) +bool DebuggerApi::SetGlobalValue(const EcmaVM *vm, Local name, Local value) { - debugger->Init(); + JSTaggedValue result; + JSTaggedValue globalObj = vm->GetGlobalEnv()->GetGlobalObject(); + JSThread *thread = vm->GetJSThread(); + + JSTaggedValue key = JSNApiHelper::ToJSTaggedValue(*name); + JSTaggedValue newVal = JSNApiHelper::ToJSTaggedValue(*value); + JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key); + if (!globalRec.IsUndefined()) { + result = SlowRuntimeStub::TryUpdateGlobalRecord(thread, key, newVal); + return !result.IsException(); + } + + JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key); + if (!globalVar.IsHole()) { + result = SlowRuntimeStub::StGlobalVar(thread, key, newVal); + return !result.IsException(); + } + + return false; } -bool DebuggerApi::HandleUncaughtException(const EcmaVM *ecmaVm, CString &message) +void DebuggerApi::HandleUncaughtException(const EcmaVM *ecmaVm, std::string &message) { JSThread *thread = ecmaVm->GetJSThread(); [[maybe_unused]] EcmaHandleScope handleScope(thread); - - if (!ecmaVm->GetJSThread()->HasPendingException()) { - return false; - } + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle exHandle(thread, thread->GetException()); if (exHandle->IsJSError()) { - JSHandle nameKey = thread->GlobalConstants()->GetHandledNameString(); + JSHandle nameKey = globalConst->GetHandledNameString(); JSHandle name(JSObject::GetProperty(thread, exHandle, nameKey).GetValue()); - JSHandle msgKey = thread->GlobalConstants()->GetHandledMessageString(); + JSHandle msgKey = globalConst->GetHandledMessageString(); JSHandle msg(JSObject::GetProperty(thread, exHandle, msgKey).GetValue()); - message = ecmascript::ConvertToString(*name) + ": " + ecmascript::ConvertToString(*msg); + message = ConvertToString(*name) + ": " + ConvertToString(*msg); } else { - [[maybe_unused]] JSHandle ecmaStr = JSTaggedValue::ToString(thread, exHandle); - message = ecmascript::ConvertToString(*ecmaStr); + JSHandle ecmaStr = JSTaggedValue::ToString(thread, exHandle); + message = ConvertToString(*ecmaStr); } thread->ClearException(); - return true; -} - -JSTaggedValue DebuggerApi::GetCurrentEvaluateEnv(const EcmaVM *ecmaVm) -{ - auto &frameHandler = ecmaVm->GetJsDebuggerManager()->GetEvalFrameHandler(); - if (frameHandler != nullptr) { - return frameHandler->GetEnv(); - } - return ecmaVm->GetJSThread()->GetCurrentLexenv(); } -Local DebuggerApi::GenerateFuncFromBuffer(const EcmaVM *ecmaVm, const void *buffer, - size_t size) +Local DebuggerApi::GenerateFuncFromBuffer(const EcmaVM *ecmaVm, const void *buffer, size_t size) { - JSPandaFileManager *mgr = EcmaVM::GetJSPandaFileManager(); + JSPandaFileManager *mgr = JSPandaFileManager::GetInstance(); const auto *jsPandaFile = mgr->LoadBufferAbc("", buffer, size); if (jsPandaFile == nullptr) { - LOG(ERROR, DEBUGGER) << "GenerateFuncFromBuffer: null jsPandaFile"; return JSValueRef::Undefined(ecmaVm); } @@ -358,7 +321,7 @@ Local DebuggerApi::GenerateFuncFromBuffer(const EcmaVM *ecmaVm, con return JSNApiHelper::ToLocal(JSHandle(ecmaVm->GetJSThread(), func)); } -Local DebuggerApi::EvaluateViaFuncCall(EcmaVM *ecmaVm, const Local &funcRef, +Local DebuggerApi::EvaluateViaFuncCall(EcmaVM *ecmaVm, Local funcRef, std::shared_ptr &frameHandler) { JSNApi::EnableUserUncaughtErrorHandler(ecmaVm); diff --git a/ecmascript/tooling/interface/debugger_api.h b/ecmascript/tooling/backend/debugger_api.h similarity index 62% rename from ecmascript/tooling/interface/debugger_api.h rename to ecmascript/tooling/backend/debugger_api.h index 6c81ca8e70cfb469a3a655b852cf8da9b628c1a7..6852d7579aae002e4c93471f18a443ed9a929440 100644 --- a/ecmascript/tooling/interface/debugger_api.h +++ b/ecmascript/tooling/backend/debugger_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,17 +13,16 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_TOOLING_INTERFACE_DEBUGGER_API_H -#define ECMASCRIPT_TOOLING_INTERFACE_DEBUGGER_API_H +#ifndef ECMASCRIPT_TOOLING_BACKEND_DEBUGGER_API_H +#define ECMASCRIPT_TOOLING_BACKEND_DEBUGGER_API_H #include #include "ecmascript/common.h" -#include "ecmascript/mem/c_string.h" +#include "ecmascript/jspandafile/scope_info_extractor.h" #include "ecmascript/napi/include/jsnapi.h" -#include "ecmascript/scope_info_extractor.h" #include "ecmascript/lexical_env.h" -#include "ecmascript/tooling/interface/js_debug_interface.h" +#include "ecmascript/tooling/backend/js_debugger_interface.h" namespace panda { namespace ecmascript { @@ -31,10 +30,9 @@ class InterpretedFrameHandler; class EcmaVM; class JSMethod; class JSThread; - namespace tooling { class JSDebugger; -} // tooling +} } // ecmascript } // panda @@ -47,36 +45,34 @@ enum StackState { class PUBLIC_API DebuggerApi { public: - // CString - static uint64_t CStringToULL(const CString &str); - static CString ToCString(int32_t number); - static CString ConvertToString(const std::string &str); - // InterpretedFrameHandler static uint32_t GetStackDepth(const EcmaVM *ecmaVm); static std::shared_ptr NewFrameHandler(const EcmaVM *ecmaVm); static bool StackWalker(const EcmaVM *ecmaVm, std::function func); static uint32_t GetBytecodeOffset(const EcmaVM *ecmaVm); static JSMethod *GetMethod(const EcmaVM *ecmaVm); - static void SetClosureVariables(const EcmaVM *ecmaVm, const InterpretedFrameHandler *frameHandler, - Local &localObj); - static Local GetVRegValue(const EcmaVM *ecmaVm, size_t index); - static void SetVRegValue(const EcmaVM *ecmaVm, size_t index, Local value); static uint32_t GetBytecodeOffset(const InterpretedFrameHandler *frameHandler); static JSMethod *GetMethod(const InterpretedFrameHandler *frameHandler); static JSTaggedValue GetEnv(const InterpretedFrameHandler *frameHandler); static JSTaggedType *GetSp(const InterpretedFrameHandler *frameHandler); + static int32_t GetVregIndex(const InterpretedFrameHandler *frameHandler, std::string_view name); static Local GetVRegValue(const EcmaVM *ecmaVm, - const InterpretedFrameHandler *frameHandler, size_t index); + const InterpretedFrameHandler *frameHandler, size_t index); + static void SetVRegValue(InterpretedFrameHandler *frameHandler, size_t index, Local value); + + static Local GetProperties(const EcmaVM *ecmaVm, const InterpretedFrameHandler *frameHandler, + int32_t level, uint32_t slot); + static void SetProperties(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + int32_t level, uint32_t slot, Local value); + static std::pair GetLevelSlot(const InterpretedFrameHandler *frameHandler, std::string_view name); + static Local GetGlobalValue(const EcmaVM *vm, Local name); + static bool SetGlobalValue(const EcmaVM *vm, Local name, Local value); // JSThread static Local GetAndClearException(const EcmaVM *ecmaVm); static void SetException(const EcmaVM *ecmaVm, Local exception); static void ClearException(const EcmaVM *ecmaVm); - // EcmaVM - static const panda_file::File *FindPandaFile(const EcmaVM *ecmaVm, const CString &fileName); - // NumberHelper static double StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix); @@ -85,26 +81,16 @@ public: static void DestroyJSDebugger(JSDebugger *debugger); static void RegisterHooks(JSDebugger *debugger, PtHooks *hooks); static bool SetBreakpoint(JSDebugger *debugger, const JSPtLocation &location, - const Local &condFuncRef); + Local condFuncRef); static bool RemoveBreakpoint(JSDebugger *debugger, const JSPtLocation &location); - - // JSMehthod - static CString ParseFunctionName(const JSMethod *method); - - // ScopeInfo - static Local GetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t slot); - static void SetProperties(const EcmaVM *ecmaVm, int32_t level, uint32_t slot, Local value); - static bool EvaluateLexicalValue(const EcmaVM *ecmaVm, const CString &name, int32_t &level, uint32_t &slot); - static Local GetLexicalValueInfo(const EcmaVM *ecmaVm, const CString &name); - static void InitJSDebugger(JSDebugger *debugger); - static bool HandleUncaughtException(const EcmaVM *ecmaVm, CString &message); - static Local GenerateFuncFromBuffer(const EcmaVM *ecmaVm, const void *buffer, size_t size); - static Local EvaluateViaFuncCall(EcmaVM *ecmaVm, const Local &funcRef, + static void HandleUncaughtException(const EcmaVM *ecmaVm, std::string &message); + static Local EvaluateViaFuncCall(EcmaVM *ecmaVm, Local funcRef, std::shared_ptr &frameHandler); + static Local GenerateFuncFromBuffer(const EcmaVM *ecmaVm, const void *buffer, size_t size); -private: - static JSTaggedValue GetCurrentEvaluateEnv(const EcmaVM *ecmaVm); + // JSMethod + static std::string ParseFunctionName(const JSMethod *method); }; } // namespace panda::ecmascript::tooling -#endif // ECMASCRIPT_TOOLING_DEBUGGER_API_H +#endif // ECMASCRIPT_TOOLING_BACKEND_DEBUGGER_API_H diff --git a/ecmascript/tooling/backend/debugger_executor.cpp b/ecmascript/tooling/backend/debugger_executor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..92427c42667d5efe387e7375da0f96388981c841 --- /dev/null +++ b/ecmascript/tooling/backend/debugger_executor.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/tooling/backend/debugger_executor.h" + +#include "ecmascript/tooling/backend/debugger_api.h" +#include "ecmascript/tooling/interface/js_debugger_manager.h" +#include "libpandabase/utils/logger.h" + +namespace panda::ecmascript::tooling { +void DebuggerExecutor::Initialize(const EcmaVM *vm) +{ + Local globalObj = JSNApi::GetGlobalObject(vm); + globalObj->Set(vm, StringRef::NewFromUtf8(vm, "debuggerSetValue"), FunctionRef::New( + const_cast(vm), DebuggerExecutor::DebuggerSetValue, nullptr)); + globalObj->Set(vm, StringRef::NewFromUtf8(vm, "debuggerGetValue"), FunctionRef::New( + const_cast(vm), DebuggerExecutor::DebuggerGetValue, nullptr)); +} + +Local DebuggerExecutor::DebuggerGetValue(EcmaVM *vm, [[maybe_unused]] Local thisArg, + const Local *argv, + int32_t length, [[maybe_unused]] void *data) +{ + if (length != NUM_ARGS) { + return JSValueRef::Undefined(vm); + } + Local name = argv[0]; + if (!name->IsString()) { + return JSValueRef::Undefined(vm); + } + Local isThrow = argv[1]; + + auto &frameHandler = vm->GetJsDebuggerManager()->GetEvalFrameHandler(); + ASSERT(frameHandler); + + Local value = GetValue(vm, frameHandler.get(), Local(name)); + if (!value.IsEmpty() && !value->IsException()) { + return value; + } + + if (!isThrow->ToBoolean(vm)->Value()) { + DebuggerApi::ClearException(vm); + return JSValueRef::Undefined(vm); + } + + std::string varName = Local(name)->ToString(); + ThrowException(vm, varName + " is not defined"); + return JSValueRef::Exception(vm); +} + +Local DebuggerExecutor::DebuggerSetValue(EcmaVM *vm, [[maybe_unused]] Local thisArg, + const Local *argv, + int32_t length, [[maybe_unused]] void *data) +{ + if (length != NUM_ARGS) { + return JSValueRef::Undefined(vm); + } + Local name = argv[0]; + if (!name->IsString()) { + return JSValueRef::Undefined(vm); + } + Local value = argv[1]; + + auto &frameHandler = vm->GetJsDebuggerManager()->GetEvalFrameHandler(); + ASSERT(frameHandler); + + if (SetValue(vm, frameHandler.get(), Local(name), value)) { + return value; + } + + std::string varName = StringRef::Cast(*name)->ToString(); + ThrowException(vm, varName + " is not defined"); + return JSValueRef::Exception(vm); +} + +Local DebuggerExecutor::GetValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + Local name) +{ + Local value; + value = GetLocalValue(vm, frameHandler, name); + if (!value.IsEmpty()) { + return value; + } + value = GetLexicalValue(vm, frameHandler, name); + if (!value.IsEmpty()) { + return value; + } + value = GetGlobalValue(vm, name); + if (!value.IsEmpty() && !value->IsException()) { + return value; + } + + return Local(); +} + +bool DebuggerExecutor::SetValue(const EcmaVM *vm, InterpretedFrameHandler *frameHandler, + Local name, Local value) +{ + if (SetLocalValue(vm, frameHandler, name, value)) { + return true; + } + if (SetLexicalValue(vm, frameHandler, name, value)) { + return true; + } + if (SetGlobalValue(vm, name, value)) { + return true; + } + + return false; +} + +void DebuggerExecutor::ThrowException(const EcmaVM *vm, const std::string &error) +{ + Local msg = StringRef::NewFromUtf8(vm, error.c_str()); + Local exception = Exception::ReferenceError(vm, msg); + JSNApi::ThrowException(vm, exception); +} + +Local DebuggerExecutor::GetLocalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + Local name) +{ + Local result; + + int32_t index = DebuggerApi::GetVregIndex(frameHandler, name->ToString()); + if (index == -1) { + return result; + } + + result = DebuggerApi::GetVRegValue(vm, frameHandler, index); + return result; +} + +bool DebuggerExecutor::SetLocalValue(const EcmaVM *vm, InterpretedFrameHandler *frameHandler, + Local name, Local value) +{ + std::string varName = name->ToString(); + int32_t index = DebuggerApi::GetVregIndex(frameHandler, varName); + if (index == -1) { + return false; + } + + DebuggerApi::SetVRegValue(frameHandler, index, value); + vm->GetJsDebuggerManager()->NotifyLocalScopeUpdated(varName, value); + return true; +} + +Local DebuggerExecutor::GetLexicalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + Local name) +{ + Local result; + + auto [level, slot] = DebuggerApi::GetLevelSlot(frameHandler, name->ToString()); + if (level == -1) { + return result; + } + + result = DebuggerApi::GetProperties(vm, frameHandler, level, slot); + return result; +} + +bool DebuggerExecutor::SetLexicalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + Local name, Local value) +{ + std::string varName = name->ToString(); + auto [level, slot] = DebuggerApi::GetLevelSlot(frameHandler, varName); + if (level == -1) { + return false; + } + + DebuggerApi::SetProperties(vm, frameHandler, level, slot, value); + vm->GetJsDebuggerManager()->NotifyLocalScopeUpdated(varName, value); + return true; +} + +Local DebuggerExecutor::GetGlobalValue(const EcmaVM *vm, Local name) +{ + return DebuggerApi::GetGlobalValue(vm, name); +} + +bool DebuggerExecutor::SetGlobalValue(const EcmaVM *vm, Local name, Local value) +{ + return DebuggerApi::SetGlobalValue(vm, name, value); +} +} // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/backend/debugger_executor.h b/ecmascript/tooling/backend/debugger_executor.h new file mode 100644 index 0000000000000000000000000000000000000000..841bb979a1ae6e7efa7c8653668d5c9e4cf5dc43 --- /dev/null +++ b/ecmascript/tooling/backend/debugger_executor.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_TOOLING_BACKEND_DEBUGGER_EXECUTOR_H +#define ECMASCRIPT_TOOLING_BACKEND_DEBUGGER_EXECUTOR_H + +#include "ecmascript/napi/include/jsnapi.h" + +namespace panda::ecmascript { +class InterpretedFrameHandler; +namespace tooling { +class DebuggerExecutor { +public: + DebuggerExecutor() = default; + ~DebuggerExecutor() = default; + + static void Initialize(const EcmaVM *vm); + + static Local GetValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + Local name); + static bool SetValue(const EcmaVM *vm, InterpretedFrameHandler *frameHandler, + Local name, Local value); + +private: + NO_COPY_SEMANTIC(DebuggerExecutor); + NO_MOVE_SEMANTIC(DebuggerExecutor); + + static Local DebuggerGetValue(EcmaVM *vm, Local thisArg, const Local *argv, + int32_t length, void *data); + static Local DebuggerSetValue(EcmaVM *vm, Local thisArg, const Local *argv, + int32_t length, void *data); + + static void ThrowException(const EcmaVM *vm, const std::string &error); + + static Local GetLocalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + Local name); + static Local GetLexicalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + Local name); + static Local GetGlobalValue(const EcmaVM *vm, Local name); + + static bool SetLocalValue(const EcmaVM *vm, InterpretedFrameHandler *frameHandler, + Local name, Local value); + static bool SetLexicalValue(const EcmaVM *vm, const InterpretedFrameHandler *frameHandler, + Local name, Local value); + static bool SetGlobalValue(const EcmaVM *vm, Local name, Local value); + + constexpr static int32_t NUM_ARGS = 2; +}; +} // namespace tooling +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_TOOLING_BACKEND_DEBUGGER_EXECUTOR_H diff --git a/ecmascript/tooling/interface/js_debugger.cpp b/ecmascript/tooling/backend/js_debugger.cpp similarity index 34% rename from ecmascript/tooling/interface/js_debugger.cpp rename to ecmascript/tooling/backend/js_debugger.cpp index ca50543b68368e32db20e7d78afabdf6fd9ebc03..633f8cad4bc43d251abec02fb1fdb3ba487cafd4 100644 --- a/ecmascript/tooling/interface/js_debugger.cpp +++ b/ecmascript/tooling/backend/js_debugger.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,25 +13,19 @@ * limitations under the License. */ -#include "ecmascript/tooling/interface/js_debugger.h" +#include "ecmascript/tooling/backend/js_debugger.h" #include "ecmascript/base/builtins_base.h" #include "ecmascript/ecma_macros.h" #include "ecmascript/global_env.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/interpreter/frame_handler.h" -#include "ecmascript/interpreter/slow_runtime_stub.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/js_thread.h" -#include "ecmascript/tooling/interface/js_debugger_manager.h" -#include "ecmascript/napi/jsnapi_helper-inl.h" -#include "runtime/tooling/pt_method_private.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::Program; using panda::ecmascript::base::BuiltinsBase; -bool JSDebugger::SetBreakpoint(const JSPtLocation &location, const Local &condFuncRef) +bool JSDebugger::SetBreakpoint(const JSPtLocation &location, Local condFuncRef) { JSMethod *method = FindMethod(location); if (method == nullptr) { @@ -108,8 +102,8 @@ bool JSDebugger::HandleBreakpoint(const JSMethod *method, uint32_t bcOffset) } } - auto *pf = method->GetPandaFile(); - JSPtLocation location {pf->GetFilename().c_str(), method->GetFileId(), bcOffset}; + auto *pf = method->GetJSPandaFile(); + JSPtLocation location {pf->GetJSPandaFileDesc().c_str(), method->GetMethodId(), bcOffset}; hooks_->Breakpoint(location); return true; @@ -121,8 +115,8 @@ void JSDebugger::HandleExceptionThrowEvent(const JSThread *thread, const JSMetho return; } - auto *pf = method->GetPandaFile(); - JSPtLocation throwLocation {pf->GetFilename().c_str(), method->GetFileId(), bcOffset}; + auto *pf = method->GetJSPandaFile(); + JSPtLocation throwLocation {pf->GetJSPandaFileDesc().c_str(), method->GetMethodId(), bcOffset}; hooks_->Exception(throwLocation); } @@ -133,8 +127,8 @@ bool JSDebugger::HandleStep(const JSMethod *method, uint32_t bcOffset) return false; } - auto *pf = method->GetPandaFile(); - JSPtLocation location {pf->GetFilename().c_str(), method->GetFileId(), bcOffset}; + auto *pf = method->GetJSPandaFile(); + JSPtLocation location {pf->GetJSPandaFileDesc().c_str(), method->GetMethodId(), bcOffset}; return hooks_->SingleStep(location); } @@ -142,12 +136,12 @@ bool JSDebugger::HandleStep(const JSMethod *method, uint32_t bcOffset) std::optional JSDebugger::FindBreakpoint(const JSMethod *method, uint32_t bcOffset) const { for (const auto &bp : breakpoints_) { - if (bp.GetBytecodeOffset() == bcOffset && bp.GetMethod()->GetPandaFile()->GetFilename() == - method->GetPandaFile()->GetFilename() && bp.GetMethod()->GetFileId() == method->GetFileId()) { + if (bp.GetBytecodeOffset() == bcOffset && + bp.GetMethod()->GetJSPandaFile()->GetJSPandaFileDesc() == method->GetJSPandaFile()->GetJSPandaFileDesc() && + bp.GetMethod()->GetMethodId() == method->GetMethodId()) { return bp; } } - return {}; } @@ -167,13 +161,13 @@ bool JSDebugger::RemoveBreakpoint(const JSMethod *method, uint32_t bcOffset) JSMethod *JSDebugger::FindMethod(const JSPtLocation &location) const { JSMethod *method = nullptr; - EcmaVM::GetJSPandaFileManager()->EnumerateJSPandaFiles([&method, location]( + ::panda::ecmascript::JSPandaFileManager::GetInstance()->EnumerateJSPandaFiles([&method, location]( const panda::ecmascript::JSPandaFile *jsPandaFile) { - if (CString(location.GetPandaFile()) == jsPandaFile->GetJSPandaFileDesc()) { + if (jsPandaFile->GetJSPandaFileDesc() == location.GetPandaFile()) { JSMethod *methodsData = jsPandaFile->GetMethods(); uint32_t numberMethods = jsPandaFile->GetNumMethods(); for (uint32_t i = 0; i < numberMethods; ++i) { - if (methodsData[i].GetFileId() == location.GetMethodId()) { + if (methodsData[i].GetMethodId() == location.GetMethodId()) { method = methodsData + i; return false; } @@ -183,206 +177,4 @@ JSMethod *JSDebugger::FindMethod(const JSPtLocation &location) const }); return method; } - -JSTaggedValue JSDebugger::DebuggerSetValue(EcmaRuntimeCallInfo *argv) -{ - LOG(INFO, DEBUGGER) << "DebuggerSetValue: called"; - auto localEvalFunc = [](const EcmaVM *ecmaVm, InterpretedFrameHandler *frameHandler, int32_t regIndex, - const CString &varName, Local value) { - JSTaggedValue newVal = JSNApiHelper::ToJSTaggedValue(*value); - frameHandler->SetVRegValue(regIndex, newVal); - ecmaVm->GetJsDebuggerManager()->NotifyLocalScopeUpdated(varName, value); - return newVal; - }; - - auto lexEvalFunc = [](const EcmaVM *ecmaVm, int32_t level, uint32_t slot, - const CString &varName, Local value) { - DebuggerApi::SetProperties(ecmaVm, level, slot, value); - if (level == 0) { - // local closure variable - ecmaVm->GetJsDebuggerManager()->NotifyLocalScopeUpdated(varName, value); - } - return JSNApiHelper::ToJSTaggedValue(*value); - }; - - auto globalEvalFunc = [](const EcmaVM *ecmaVm, JSTaggedValue key, - const CString &varName, JSTaggedValue value) { - JSTaggedValue result = SetGlobalValue(ecmaVm, key, value); - if (!result.IsException()) { - return value; - } - - JSThread *thread = ecmaVm->GetJSThread(); - CString msg = varName + " is not defined"; - THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.data(), JSTaggedValue::Exception()); - }; - - return Evaluate(argv, localEvalFunc, lexEvalFunc, globalEvalFunc); -} - -JSTaggedValue JSDebugger::DebuggerGetValue(EcmaRuntimeCallInfo *argv) -{ - LOG(INFO, DEBUGGER) << "DebuggerGetValue: called"; - auto localEvalFunc = [](const EcmaVM *, InterpretedFrameHandler *frameHandler, int32_t regIndex, - const CString &, Local) { - return frameHandler->GetVRegValue(regIndex); - }; - - auto lexEvalFunc = [](const EcmaVM *ecmaVm, int32_t level, uint32_t slot, - const CString &, Local) { - Local valRef = DebuggerApi::GetProperties(ecmaVm, level, slot); - return JSNApiHelper::ToJSTaggedValue(*valRef); - }; - - auto globalEvalFunc = [](const EcmaVM *ecmaVm, JSTaggedValue key, - const CString &varName, JSTaggedValue isThrow) { - JSTaggedValue globalVal = GetGlobalValue(ecmaVm, key); - if (!globalVal.IsException()) { - return globalVal; - } - - JSThread *thread = ecmaVm->GetJSThread(); - if (isThrow.ToBoolean()) { - CString msg = varName + " is not defined"; - THROW_REFERENCE_ERROR_AND_RETURN(thread, msg.data(), JSTaggedValue::Exception()); - } - // in case of `typeof`, return undefined instead of exception - thread->ClearException(); - return JSTaggedValue::Undefined(); - }; - - return Evaluate(argv, localEvalFunc, lexEvalFunc, globalEvalFunc); -} - -JSTaggedValue JSDebugger::Evaluate(EcmaRuntimeCallInfo *argv, LocalEvalFunc localEvalFunc, - LexEvalFunc lexEvalFunc, GlobalEvalFunc globalEvalFunc) -{ - LOG(INFO, DEBUGGER) << "Evaluate: called"; - ASSERT(argv); - JSThread *thread = argv->GetThread(); - const EcmaVM *ecmaVm = thread->GetEcmaVM(); - [[maybe_unused]] EcmaHandleScope handleScope(thread); - - // The arg2 is the new value for setter and throw flag for getter - JSHandle arg1 = BuiltinsBase::GetCallArg(argv, 0); - JSHandle arg2 = BuiltinsBase::GetCallArg(argv, 1); - CString varName = ConvertToString(arg1.GetTaggedValue()); - Local valRef = JSNApiHelper::ToLocal(arg2); - LOG(INFO, DEBUGGER) << "Evaluate: varName = " << varName; - - auto &frameHandler = ecmaVm->GetJsDebuggerManager()->GetEvalFrameHandler(); - ASSERT(frameHandler); - JSMethod *method = frameHandler->GetMethod(); - int32_t regIndex = -1; - bool found = EvaluateLocalValue(method, thread, varName, regIndex); - if (found) { - LOG(ERROR, DEBUGGER) << "Evaluate: found regIndex = " << regIndex; - return localEvalFunc(ecmaVm, frameHandler.get(), regIndex, varName, valRef); - } - - int32_t level = 0; - uint32_t slot = 0; - found = DebuggerApi::EvaluateLexicalValue(ecmaVm, varName, level, slot); - if (found) { - LOG(ERROR, DEBUGGER) << "Evaluate: found level = " << level; - return lexEvalFunc(ecmaVm, level, slot, varName, valRef); - } - - return globalEvalFunc(ecmaVm, arg1.GetTaggedValue(), varName, arg2.GetTaggedValue()); -} - -JSTaggedValue JSDebugger::GetGlobalValue(const EcmaVM *ecmaVm, JSTaggedValue key) -{ - JSTaggedValue globalObj = ecmaVm->GetGlobalEnv()->GetGlobalObject(); - JSThread *thread = ecmaVm->GetJSThread(); - - JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key); - if (!globalRec.IsUndefined()) { - ASSERT(globalRec.IsPropertyBox()); - return PropertyBox::Cast(globalRec.GetTaggedObject())->GetValue(); - } - - JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key); - if (!globalVar.IsHole()) { - return globalVar; - } else { - return SlowRuntimeStub::TryLdGlobalByName(thread, globalObj, key); - } - - return JSTaggedValue::Exception(); -} - -JSTaggedValue JSDebugger::SetGlobalValue(const EcmaVM *ecmaVm, JSTaggedValue key, JSTaggedValue newVal) -{ - JSTaggedValue globalObj = ecmaVm->GetGlobalEnv()->GetGlobalObject(); - JSThread *thread = ecmaVm->GetJSThread(); - - JSTaggedValue globalRec = SlowRuntimeStub::LdGlobalRecord(thread, key); - if (!globalRec.IsUndefined()) { - return SlowRuntimeStub::TryUpdateGlobalRecord(thread, key, newVal); - } - - JSTaggedValue globalVar = FastRuntimeStub::GetGlobalOwnProperty(thread, globalObj, key); - if (!globalVar.IsHole()) { - return SlowRuntimeStub::StGlobalVar(thread, key, newVal); - } - - return JSTaggedValue::Exception(); -} - -bool JSDebugger::EvaluateLocalValue(JSMethod *method, JSThread *thread, const CString &varName, int32_t ®Index) -{ - if (method->IsNative()) { - LOG(ERROR, DEBUGGER) << "EvaluateLocalValue: native frame not support"; - THROW_TYPE_ERROR_AND_RETURN(thread, "native frame not support", false); - } - PtJSExtractor *extractor = thread->GetEcmaVM()->GetDebugInfoExtractor(method->GetPandaFile()); - if (extractor == nullptr) { - LOG(ERROR, DEBUGGER) << "EvaluateLocalValue: extractor is null"; - THROW_TYPE_ERROR_AND_RETURN(thread, "extractor is null", false); - } - - auto varInfos = extractor->GetLocalVariableTable(method->GetFileId()); - for (const auto &varInfo : varInfos) { - if (varInfo.name == std::string(varName)) { - regIndex = varInfo.reg_number; - return true; - } - } - - return false; -} - -void JSDebugger::Init() -{ - JSThread *thread = ecmaVm_->GetJSThread(); - [[maybe_unused]] EcmaHandleScope scope(thread); - - ObjectFactory *factory = ecmaVm_->GetFactory(); - constexpr int32_t NUM_ARGS = 2; - JSHandle getter(factory->NewFromUtf8("debuggerGetValue")); - SetGlobalFunction(getter, JSDebugger::DebuggerGetValue, NUM_ARGS); - JSHandle setter(factory->NewFromUtf8("debuggerSetValue")); - SetGlobalFunction(setter, JSDebugger::DebuggerSetValue, NUM_ARGS); -} - -void JSDebugger::SetGlobalFunction(const JSHandle &funcName, - EcmaEntrypoint nativeFunc, int32_t numArgs) const -{ - ObjectFactory *factory = ecmaVm_->GetFactory(); - JSThread *thread = ecmaVm_->GetJSThread(); - [[maybe_unused]] EcmaHandleScope scope(thread); - JSHandle env = ecmaVm_->GetGlobalEnv(); - JSHandle globalObject(thread, env->GetGlobalObject()); - - JSHandle jsFunc = factory->NewJSFunction(env, reinterpret_cast(nativeFunc)); - JSFunction::SetFunctionLength(thread, jsFunc, JSTaggedValue(numArgs)); - JSHandle baseFunc(jsFunc); - JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); - JSFunction::SetFunctionName(thread, baseFunc, funcName, undefined); - - JSHandle funcHandle(jsFunc); - PropertyDescriptor desc(thread, JSHandle(funcHandle), true, false, true); - JSObject::DefineOwnProperty(thread, globalObject, funcName, desc); -} -} // panda::ecmascript::tooling \ No newline at end of file +} // namespace panda::tooling::ecmascript diff --git a/ecmascript/tooling/interface/js_debugger.h b/ecmascript/tooling/backend/js_debugger.h similarity index 65% rename from ecmascript/tooling/interface/js_debugger.h rename to ecmascript/tooling/backend/js_debugger.h index e91aa23be1239e49a4429b8db3b625752a40fe98..56663a13b18959065c933c3b05f03dd9fbae1232 100644 --- a/ecmascript/tooling/interface/js_debugger.h +++ b/ecmascript/tooling/backend/js_debugger.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 Huawei Device Co., Ltd. + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,26 +13,16 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_TOOLING_INTERFACE_JS_DEBUGGER_H -#define ECMASCRIPT_TOOLING_INTERFACE_JS_DEBUGGER_H +#ifndef ECMASCRIPT_TOOLING_BACKEND_JS_DEBUGGER_H +#define ECMASCRIPT_TOOLING_BACKEND_JS_DEBUGGER_H #include "ecmascript/ecma_vm.h" #include "ecmascript/js_method.h" -#include "ecmascript/mem/c_containers.h" -#include "ecmascript/tooling/interface/debugger_api.h" +#include "ecmascript/tooling/backend/debugger_api.h" #include "ecmascript/tooling/interface/notification_manager.h" #include "ecmascript/tooling/interface/js_debugger_manager.h" -#include "ecmascript/js_tagged_value.h" -#include "ecmascript/js_handle.h" -#include "ecmascript/ecma_runtime_call_info.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::CUnorderedSet; -using panda::ecmascript::JSHandle; -using panda::ecmascript::JSTaggedValue; -using panda::ecmascript::EcmaEntrypoint; -using panda::ecmascript::EcmaRuntimeCallInfo; - class JSBreakpoint { public: // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) @@ -79,7 +69,7 @@ public: class JSDebugger : public JSDebugInterface, RuntimeListener { public: - JSDebugger(const EcmaVM *vm) : ecmaVm_(vm) + explicit JSDebugger(const EcmaVM *vm) : ecmaVm_(vm) { notificationMgr_ = ecmaVm_->GetJsDebuggerManager()->GetNotificationManager(); notificationMgr_->AddListener(this); @@ -102,7 +92,7 @@ public: hooks_ = nullptr; } - bool SetBreakpoint(const JSPtLocation &location, const Local &condFuncRef) override; + bool SetBreakpoint(const JSPtLocation &location, Local condFuncRef) override; bool RemoveBreakpoint(const JSPtLocation &location) override; void BytecodePcChanged(JSThread *thread, JSMethod *method, uint32_t bcOffset) override; void LoadModule(std::string_view filename) override @@ -119,7 +109,6 @@ public: } hooks_->VmStart(); } - void VmDeath() override { if (hooks_ == nullptr) { @@ -127,34 +116,22 @@ public: } hooks_->VmDeath(); } - - void Init(); + void PendingJobEntry() override + { + if (hooks_ == nullptr) { + return; + } + hooks_->PendingJobEntry(); + } private: - using LocalEvalFunc = - std::function)>; - using LexEvalFunc = - std::function)>; - using GlobalEvalFunc = - std::function; - - JSMethod *FindMethod(const JSPtLocation &location) const; + JSMethod *FindMethod(const JSPtLocation &location) const; std::optional FindBreakpoint(const JSMethod *method, uint32_t bcOffset) const; bool RemoveBreakpoint(const JSMethod *method, uint32_t bcOffset); void HandleExceptionThrowEvent(const JSThread *thread, const JSMethod *method, uint32_t bcOffset); bool HandleStep(const JSMethod *method, uint32_t bcOffset); bool HandleBreakpoint(const JSMethod *method, uint32_t bcOffset); - void SetGlobalFunction(const JSHandle &funcName, EcmaEntrypoint nativeFunc, int32_t numArgs) const; - static JSTaggedValue Evaluate(EcmaRuntimeCallInfo *argv, LocalEvalFunc localEvalFunc, - LexEvalFunc lexEvalFunc, GlobalEvalFunc globalEvalFunc); - static JSTaggedValue DebuggerSetValue(EcmaRuntimeCallInfo *argv); - static JSTaggedValue DebuggerGetValue(EcmaRuntimeCallInfo *argv); - static JSTaggedValue GetGlobalValue(const EcmaVM *ecmaVm, JSTaggedValue key); - static JSTaggedValue SetGlobalValue(const EcmaVM *ecmaVm, JSTaggedValue key, JSTaggedValue value); - static bool EvaluateLocalValue(JSMethod *method, JSThread *thread, const CString &varName, int32_t ®Index); - const EcmaVM *ecmaVm_; PtHooks *hooks_ {nullptr}; NotificationManager *notificationMgr_ {nullptr}; @@ -163,4 +140,4 @@ private: }; } // namespace panda::ecmascript::tooling -#endif // ECMASCRIPT_TOOLING_JS_DEBUGGER_H +#endif // ECMASCRIPT_TOOLING_BACKEND_JS_DEBUGGER_H diff --git a/ecmascript/tooling/interface/js_debug_interface.h b/ecmascript/tooling/backend/js_debugger_interface.h similarity index 90% rename from ecmascript/tooling/interface/js_debug_interface.h rename to ecmascript/tooling/backend/js_debugger_interface.h index 35d8b1ffc593fb37b4bae8561f50e7ff4db1ba09..08f7943d944ebe18f83d406902f4a0ba5238e99c 100644 --- a/ecmascript/tooling/interface/js_debug_interface.h +++ b/ecmascript/tooling/backend/js_debugger_interface.h @@ -19,7 +19,10 @@ #include #include "ecmascript/napi/include/jsnapi.h" -#include "ecmascript/tooling/interface/js_pt_location.h" +#include "ecmascript/tooling/backend/js_pt_location.h" +#include "libpandafile/file.h" +#include "libpandabase/macros.h" +#include "libpandabase/utils/expected.h" namespace panda::ecmascript::tooling { struct JSPtStepRange { @@ -61,6 +64,11 @@ public: */ virtual void LoadModule(std::string_view pandaFileName) = 0; + /** + * \brief called before executing pending job + */ + virtual void PendingJobEntry() = 0; + /** * \brief called by the ecmavm when virtual machine start initialization */ @@ -71,8 +79,6 @@ public: */ virtual void VmDeath() = 0; - virtual void Paused(PauseReason reason) = 0; - virtual void Exception(const JSPtLocation &location) = 0; virtual bool SingleStep(const JSPtLocation &location) = 0; @@ -106,7 +112,7 @@ public: * @param condition Optional condition * @return Error if any errors occur */ - virtual bool SetBreakpoint(const JSPtLocation &location, const Local &condFuncRef) = 0; + virtual bool SetBreakpoint(const JSPtLocation &location, Local condFuncRef) = 0; /** * \brief Remove breakpoint from \param location diff --git a/ecmascript/tooling/pt_js_extractor.cpp b/ecmascript/tooling/backend/js_pt_extractor.cpp similarity index 68% rename from ecmascript/tooling/pt_js_extractor.cpp rename to ecmascript/tooling/backend/js_pt_extractor.cpp index aa83a1ffcfcef470b73e7960c47c48990d29a69b..c37311606b5a6c8716bd28bdd30495c6f2255255 100644 --- a/ecmascript/tooling/pt_js_extractor.cpp +++ b/ecmascript/tooling/backend/js_pt_extractor.cpp @@ -13,18 +13,17 @@ * limitations under the License. */ -#include "ecmascript/tooling/interface/debugger_api.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/backend/js_pt_extractor.h" + +#include "ecmascript/tooling/backend/debugger_api.h" namespace panda::ecmascript::tooling { -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.startBcOffset && pc < range.endBcOffset) { @@ -34,7 +33,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 +54,7 @@ bool PtJSExtractor::SingleStepper::StepComplete(uint32_t bcOffset) const } break; } - case SingleStepper::Type::OUT: { + case Type::OUT: { if (stackDepth_ <= stackDepth) { return false; } @@ -69,26 +68,26 @@ bool PtJSExtractor::SingleStepper::StepComplete(uint32_t bcOffset) const return true; } -std::unique_ptr PtJSExtractor::GetStepIntoStepper(const EcmaVM *ecmaVm) +std::unique_ptr JSPtExtractor::GetStepIntoStepper(const EcmaVM *ecmaVm) { return GetStepper(ecmaVm, SingleStepper::Type::INTO); } -std::unique_ptr PtJSExtractor::GetStepOverStepper(const EcmaVM *ecmaVm) +std::unique_ptr JSPtExtractor::GetStepOverStepper(const EcmaVM *ecmaVm) { return GetStepper(ecmaVm, SingleStepper::Type::OVER); } -std::unique_ptr PtJSExtractor::GetStepOutStepper(const EcmaVM *ecmaVm) +std::unique_ptr JSPtExtractor::GetStepOutStepper(const EcmaVM *ecmaVm) { return GetStepper(ecmaVm, SingleStepper::Type::OUT); } -CList PtJSExtractor::GetStepRanges(File::EntityId methodId, uint32_t offset) +std::list JSPtExtractor::GetStepRanges(File::EntityId methodId, uint32_t offset) { - CList ranges {}; - auto table = GetLineNumberTable(methodId); - auto callbackFunc = [table, &ranges](size_t line, [[maybe_unused]] size_t column) -> bool { + std::list ranges {}; + const LineNumberTable &table = GetLineNumberTable(methodId); + auto callbackFunc = [table, &ranges](int32_t line) -> bool { for (auto it = table.begin(); it != table.end(); ++it) { auto next = it + 1; if (it->line == line) { @@ -98,21 +97,20 @@ CList PtJSExtractor::GetStepRanges(File::EntityId methodId, uint3 } return true; }; - MatchWithOffset(callbackFunc, methodId, offset); - + MatchLineWithOffset(callbackFunc, methodId, offset); return ranges; } -std::unique_ptr PtJSExtractor::GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type) +std::unique_ptr JSPtExtractor::GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type) { JSMethod *method = DebuggerApi::GetMethod(ecmaVm); ASSERT(method != nullptr); if (type == SingleStepper::Type::OUT) { - return std::make_unique(ecmaVm, method, CList {}, type); + return std::make_unique(ecmaVm, method, std::list {}, type); } - CList ranges = GetStepRanges(method->GetFileId(), DebuggerApi::GetBytecodeOffset(ecmaVm)); + std::list ranges = GetStepRanges(method->GetMethodId(), DebuggerApi::GetBytecodeOffset(ecmaVm)); return std::make_unique(ecmaVm, method, std::move(ranges), type); } } // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/pt_js_extractor.h b/ecmascript/tooling/backend/js_pt_extractor.h similarity index 57% rename from ecmascript/tooling/pt_js_extractor.h rename to ecmascript/tooling/backend/js_pt_extractor.h index e32936eb6c118484291abe638234354887e32a31..e181b8df59bcd35d44e91dc9bfe3752f20659943 100644 --- a/ecmascript/tooling/pt_js_extractor.h +++ b/ecmascript/tooling/backend/js_pt_extractor.h @@ -13,29 +13,24 @@ * limitations under the License. */ -#ifndef PANDA_TOOLING_JS_EXTRACTOR_H -#define PANDA_TOOLING_JS_EXTRACTOR_H +#ifndef ECMASCRIPT_TOOLING_BACKEND_JS_PT_EXTRACTOR_H +#define ECMASCRIPT_TOOLING_BACKEND_JS_PT_EXTRACTOR_H #include "ecmascript/js_method.h" #include "ecmascript/js_thread.h" -#include "ecmascript/mem/c_containers.h" -#include "ecmascript/tooling/interface/js_debug_interface.h" -#include "libpandafile/debug_info_extractor.h" +#include "ecmascript/jspandafile/debug_info_extractor.h" +#include "ecmascript/tooling/backend/js_debugger_interface.h" #include "libpandabase/macros.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::CList; -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: enum class Type { INTO, OVER, OUT }; - SingleStepper(const EcmaVM *ecmaVm, JSMethod *method, CList stepRanges, Type type) + SingleStepper(const EcmaVM *ecmaVm, JSMethod *method, std::list stepRanges, Type type) : ecmaVm_(ecmaVm), method_(method), stepRanges_(std::move(stepRanges)), @@ -55,21 +50,25 @@ public: const EcmaVM *ecmaVm_; JSMethod *method_; - CList stepRanges_; + std::list stepRanges_; uint32_t stackDepth_; Type type_; }; - explicit PtJSExtractor(const File *pf) : DebugInfoExtractor(pf) {} - virtual ~PtJSExtractor() = default; + explicit JSPtExtractor(const JSPandaFile *jsPandaFile) : DebugInfoExtractor(jsPandaFile) {} + virtual ~JSPtExtractor() = default; template - bool MatchWithLocation(const Callback &cb, size_t line, size_t column) + bool MatchWithLocation(const Callback &cb, int32_t line, int32_t column) { + if (line == SPECIAL_LINE_MARK) { + return false; + } + auto methods = GetMethodIdList(); for (const auto &method : methods) { - auto lineTable = GetLineNumberTable(method); - auto columnTable = GetColumnNumberTable(method); + const LineNumberTable &lineTable = GetLineNumberTable(method); + const ColumnNumberTable &columnTable = GetColumnNumberTable(method); for (uint32_t i = 0; i < lineTable.size(); i++) { if (lineTable[i].line != line) { continue; @@ -88,44 +87,39 @@ public: } template - bool MatchWithOffset(const Callback &cb, File::EntityId methodId, uint32_t offset) + bool MatchLineWithOffset(const Callback &cb, File::EntityId methodId, uint32_t offset) { - auto lineTable = GetLineNumberTable(methodId); - auto columnTable = GetColumnNumberTable(methodId); - size_t line = 0; - size_t column = 0; - - for (const auto &pair : lineTable) { - if (offset < pair.offset) { - break; - } else if (offset == pair.offset) { - line = pair.line; - break; - } - line = pair.line; + int32_t line = 0; + const LineNumberTable &lineTable = GetLineNumberTable(methodId); + auto iter = std::upper_bound(lineTable.begin(), lineTable.end(), LineTableEntry {offset, 0}); + if (iter != lineTable.begin()) { + line = (iter - 1)->line; } + return cb(line); + } - for (const auto &pair : columnTable) { - if (offset < pair.offset) { - break; - } else if (offset == pair.offset) { - column = pair.column; - break; - } - column = pair.column; + template + bool MatchColumnWithOffset(const Callback &cb, File::EntityId methodId, uint32_t offset) + { + int32_t column = 0; + const ColumnNumberTable &columnTable = GetColumnNumberTable(methodId); + auto iter = std::upper_bound(columnTable.begin(), columnTable.end(), ColumnTableEntry {offset, 0}); + if (iter != columnTable.begin()) { + column = (iter - 1)->column; } - return cb(line, column); + return cb(column); } - std::unique_ptr GetStepIntoStepper(const EcmaVM *ecmaVm); std::unique_ptr GetStepOverStepper(const EcmaVM *ecmaVm); std::unique_ptr GetStepOutStepper(const EcmaVM *ecmaVm); + constexpr static int32_t SPECIAL_LINE_MARK = -1; + private: - NO_COPY_SEMANTIC(PtJSExtractor); - NO_MOVE_SEMANTIC(PtJSExtractor); - CList GetStepRanges(File::EntityId methodId, uint32_t offset); + NO_COPY_SEMANTIC(JSPtExtractor); + NO_MOVE_SEMANTIC(JSPtExtractor); + std::list GetStepRanges(File::EntityId methodId, uint32_t offset); std::unique_ptr GetStepper(const EcmaVM *ecmaVm, SingleStepper::Type type); }; } // namespace panda::ecmascript::tooling -#endif +#endif // ECMASCRIPT_TOOLING_BACKEND_JS_PT_EXTRACTOR_H diff --git a/ecmascript/tooling/agent/js_pt_hooks.cpp b/ecmascript/tooling/backend/js_pt_hooks.cpp similarity index 65% rename from ecmascript/tooling/agent/js_pt_hooks.cpp rename to ecmascript/tooling/backend/js_pt_hooks.cpp index 0acf2f56b660b3c8342dff887f27a36a27f43023..f3af915594be023707c8b46ae9a9ab97acc20b76 100644 --- a/ecmascript/tooling/agent/js_pt_hooks.cpp +++ b/ecmascript/tooling/backend/js_pt_hooks.cpp @@ -13,8 +13,8 @@ * limitations under the License. */ -#include "ecmascript/tooling/agent/js_pt_hooks.h" -#include "ecmascript/tooling/agent/js_backend.h" +#include "ecmascript/tooling/agent/debugger_impl.h" +#include "ecmascript/tooling/backend/js_pt_hooks.h" namespace panda::ecmascript::tooling { void JSPtHooks::Breakpoint(const JSPtLocation &location) @@ -22,41 +22,33 @@ void JSPtHooks::Breakpoint(const JSPtLocation &location) LOG(DEBUG, DEBUGGER) << "JSPtHooks: Breakpoint => " << location.GetMethodId() << ": " << location.GetBytecodeOffset(); - [[maybe_unused]] LocalScope scope(backend_->ecmaVm_); - backend_->NotifyPaused(location, INSTRUMENTATION); -} - -void JSPtHooks::Paused(PauseReason reason) -{ - LOG(DEBUG, DEBUGGER) << "JSPtHooks: Paused"; - - [[maybe_unused]] LocalScope scope(backend_->ecmaVm_); - backend_->NotifyPaused({}, reason); + [[maybe_unused]] LocalScope scope(debugger_->vm_); + debugger_->NotifyPaused(location, INSTRUMENTATION); } void JSPtHooks::Exception([[maybe_unused]] const JSPtLocation &location) { LOG(DEBUG, DEBUGGER) << "JSPtHooks: Exception"; - [[maybe_unused]] LocalScope scope(backend_->ecmaVm_); + [[maybe_unused]] LocalScope scope(debugger_->vm_); - backend_->NotifyPaused({}, EXCEPTION); + debugger_->NotifyPaused({}, EXCEPTION); } bool JSPtHooks::SingleStep(const JSPtLocation &location) { LOG(DEBUG, DEBUGGER) << "JSPtHooks: SingleStep => " << location.GetBytecodeOffset(); - [[maybe_unused]] LocalScope scope(backend_->ecmaVm_); + [[maybe_unused]] LocalScope scope(debugger_->vm_); if (UNLIKELY(firstTime_)) { firstTime_ = false; - backend_->NotifyPaused({}, BREAK_ON_START); + debugger_->NotifyPaused({}, BREAK_ON_START); return false; } // pause or step complete - if (backend_->StepComplete(location)) { - backend_->NotifyPaused({}, OTHER); + if (debugger_->NotifySingleStep(location)) { + debugger_->NotifyPaused({}, OTHER); return true; } return false; @@ -66,11 +58,20 @@ void JSPtHooks::LoadModule(std::string_view pandaFileName) { LOG(INFO, DEBUGGER) << "JSPtHooks: LoadModule: " << pandaFileName; - [[maybe_unused]] LocalScope scope(backend_->ecmaVm_); + [[maybe_unused]] LocalScope scope(debugger_->vm_); static uint32_t scriptId = 0; - if (backend_->NotifyScriptParsed(scriptId++, pandaFileName.data())) { + if (debugger_->NotifyScriptParsed(scriptId++, pandaFileName.data())) { firstTime_ = true; } } + +void JSPtHooks::PendingJobEntry() +{ + LOG(DEBUG, DEBUGGER) << "JSPtHooks: PendingJobEntry"; + + [[maybe_unused]] LocalScope scope(debugger_->vm_); + + debugger_->NotifyPendingJobEntry(); +} } // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/agent/js_pt_hooks.h b/ecmascript/tooling/backend/js_pt_hooks.h similarity index 75% rename from ecmascript/tooling/agent/js_pt_hooks.h rename to ecmascript/tooling/backend/js_pt_hooks.h index 8a4e277451b51f203d3e3912603518fc7b1cd64b..29cfa9e4ce5cbbb05fd013e6bef40e8a3c748c68 100644 --- a/ecmascript/tooling/agent/js_pt_hooks.h +++ b/ecmascript/tooling/backend/js_pt_hooks.h @@ -13,29 +13,28 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_TOOLING_AGENT_JS_PT_HOOKS_H -#define ECMASCRIPT_TOOLING_AGENT_JS_PT_HOOKS_H +#ifndef ECMASCRIPT_TOOLING_BACKEND_JS_PT_HOOKS_H +#define ECMASCRIPT_TOOLING_BACKEND_JS_PT_HOOKS_H #include "libpandabase/macros.h" -#include "ecmascript/tooling/pt_js_extractor.h" +#include "ecmascript/tooling/backend/js_pt_extractor.h" #include "ecmascript/tooling/base/pt_events.h" #include "ecmascript/tooling/base/pt_script.h" -#include "ecmascript/tooling/interface/js_debug_interface.h" +#include "ecmascript/tooling/backend/js_debugger_interface.h" namespace panda::ecmascript::tooling { -class JSBackend; +class DebuggerImpl; class JSPtHooks : public PtHooks { public: - explicit JSPtHooks(JSBackend *backend) : backend_(backend) {} + explicit JSPtHooks(DebuggerImpl *debugger) : debugger_(debugger) {} ~JSPtHooks() override = default; void Breakpoint(const JSPtLocation &location) override; void LoadModule(std::string_view pandaFileName) override; - void Paused(PauseReason reason) override; void Exception(const JSPtLocation &location) override; bool SingleStep(const JSPtLocation &location) override; - + void PendingJobEntry() override; void VmStart() override {} void VmDeath() override {} @@ -43,8 +42,8 @@ private: NO_COPY_SEMANTIC(JSPtHooks); NO_MOVE_SEMANTIC(JSPtHooks); - JSBackend *backend_{nullptr}; + DebuggerImpl *debugger_ {nullptr}; bool firstTime_ {true}; }; } // namespace panda::ecmascript::tooling -#endif \ No newline at end of file +#endif // ECMASCRIPT_TOOLING_BACKEND_JS_PT_HOOKS_H \ No newline at end of file diff --git a/ecmascript/tooling/interface/js_pt_location.h b/ecmascript/tooling/backend/js_pt_location.h similarity index 89% rename from ecmascript/tooling/interface/js_pt_location.h rename to ecmascript/tooling/backend/js_pt_location.h index 0c1fd9b8ee700fbe2ce2bd36d5862123a5ecc42a..434372fa5296b3eb915cd50638487a9a42228499 100644 --- a/ecmascript/tooling/interface/js_pt_location.h +++ b/ecmascript/tooling/backend/js_pt_location.h @@ -13,12 +13,12 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_TOOLING_INTERFACE_JS_PT_LOCATION_H -#define ECMASCRIPT_TOOLING_INTERFACE_JS_PT_LOCATION_H +#ifndef ECMASCRIPT_TOOLING_BACKEND_JS_PT_LOCATION_H +#define ECMASCRIPT_TOOLING_BACKEND_JS_PT_LOCATION_H #include -#include "libpandafile/file_items.h" +#include "libpandafile/file.h" #include "libpandabase/macros.h" namespace panda::ecmascript::tooling { @@ -64,4 +64,4 @@ private: }; } // namespace panda::ecmascript::tooling -#endif // ECMASCRIPT_TOOLING_INTERFACE_JS_PT_LOCATION_H +#endif // ECMASCRIPT_TOOLING_BACKEND_JS_PT_LOCATION_H diff --git a/ecmascript/tooling/base/pt_events.cpp b/ecmascript/tooling/base/pt_events.cpp index 69a2d5b32fd7eb552b2dda2c4896a270bc7f4f13..0dce046d95928f62e298990c040c1a8aad2b0a22 100644 --- a/ecmascript/tooling/base/pt_events.cpp +++ b/ecmascript/tooling/base/pt_events.cpp @@ -16,706 +16,269 @@ #include "ecmascript/tooling/base/pt_events.h" namespace panda::ecmascript::tooling { -std::unique_ptr BreakpointResolved::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr BreakpointResolved::ToJson() const { - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "BreakpointResolved::Create params is nullptr"; - return nullptr; - } - CString error; - auto breakpointResolved = std::make_unique(); - - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "breakpointId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - breakpointResolved->breakpointId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'breakpointId' should a String;"; - } - } else { - error += "should contain 'breakpointId';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "location"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr location = Location::Create(ecmaVm, result); - if (location == nullptr) { - error += "'location' format error;"; - } else { - breakpointResolved->location_ = std::move(location); - } - } else { - error += "'exception' should a Object;"; - } - } else { - error += "should contain 'location';"; - } - if (!error.empty()) { - LOG(ERROR, DEBUGGER) << "BreakpointResolved::Create " << error; - return nullptr; - } - - return breakpointResolved; -} - -Local BreakpointResolved::ToObject(const EcmaVM *ecmaVm) -{ - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); + result->Add("breakpointId", breakpointId_.c_str()); + ASSERT(location_ != nullptr); + result->Add("location", location_->ToJson()); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "breakpointId")), - Local(StringRef::NewFromUtf8(ecmaVm, breakpointId_.c_str()))); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "location")), - Local(location_->ToObject(ecmaVm))); - - Local object = NewObject(ecmaVm); - object->Set(ecmaVm, - StringRef::NewFromUtf8(ecmaVm, "method"), - Local(StringRef::NewFromUtf8(ecmaVm, GetName().c_str()))); - object->Set(ecmaVm, StringRef::NewFromUtf8(ecmaVm, "params"), Local(params)); + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); return object; } -std::unique_ptr Paused::Create(const EcmaVM *ecmaVm, const Local ¶ms) -{ - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "Paused::Create params is nullptr"; - return nullptr; - } - CString error; - auto paused = std::make_unique(); - - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "callFrames"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsArray(ecmaVm)) { - auto array = Local(result); - uint32_t len = array->Length(ecmaVm); - Local key = JSValueRef::Undefined(ecmaVm); - for (uint32_t i = 0; i < len; ++i) { - key = IntegerRef::New(ecmaVm, i); - Local resultValue = Local(array)->Get(ecmaVm, key->ToString(ecmaVm)); - std::unique_ptr callFrame = CallFrame::Create(ecmaVm, resultValue); - if (resultValue.IsEmpty() || callFrame == nullptr) { - error += "'callFrames' format invalid;"; - } - paused->callFrames_.emplace_back(std::move(callFrame)); - } - } else { - error += "'callFrames' should a Array;"; - } - } else { - error += "should contain 'callFrames';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "reason"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paused->reason_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'reason' should a String;"; - } - } else { - error += "should contain 'reason';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "data"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'data' format error;"; - } else { - paused->data_ = std::move(obj); - } - } else { - error += "'data' should a Object;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "hitBreakpoints"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsArray(ecmaVm)) { - CVector breakPoints; - auto array = Local(result); - uint32_t len = array->Length(ecmaVm); - Local key = JSValueRef::Undefined(ecmaVm); - for (uint32_t i = 0; i < len; ++i) { - key = IntegerRef::New(ecmaVm, i); - Local resultValue = Local(array)->Get(ecmaVm, key->ToString(ecmaVm)); - if (resultValue.IsEmpty()) { - error += "'hitBreakpoints' format invalid;"; - } - breakPoints.emplace_back(DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString())); - } - paused->hitBreakpoints_ = std::move(breakPoints); - } else { - error += "'hitBreakpoints' should a Array;"; - } - } - if (!error.empty()) { - LOG(ERROR, DEBUGGER) << "Parsed::Create " << error; - return nullptr; - } - - return paused; -} - -Local Paused::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr Paused::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); + std::unique_ptr array = PtJson::CreateArray(); size_t len = callFrames_.size(); - Local values = ArrayRef::New(ecmaVm, len); for (size_t i = 0; i < len; i++) { - Local callFrame = callFrames_[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, callFrame); + ASSERT(callFrames_[i] != nullptr); + array->Push(callFrames_[i]->ToJson()); } - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "callFrames")), values); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "reason")), - Local(StringRef::NewFromUtf8(ecmaVm, reason_.c_str()))); + result->Add("callFrames", array); + result->Add("reason", reason_.c_str()); if (data_) { - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "data")), - Local(data_.value()->ToObject(ecmaVm))); + ASSERT(data_.value() != nullptr); + result->Add("data", data_.value()->ToJson()); } if (hitBreakpoints_) { + std::unique_ptr breakpoints = PtJson::CreateArray(); len = hitBreakpoints_->size(); - values = ArrayRef::New(ecmaVm, len); for (size_t i = 0; i < len; i++) { - Local id = StringRef::NewFromUtf8(ecmaVm, hitBreakpoints_.value()[i].c_str()); - values->Set(ecmaVm, i, id); + breakpoints->Push(hitBreakpoints_.value()[i].c_str()); } - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "hitBreakpoints")), values); + result->Add("hitBreakpoints", breakpoints); } - Local object = NewObject(ecmaVm); - object->Set(ecmaVm, - StringRef::NewFromUtf8(ecmaVm, "method"), - Local(StringRef::NewFromUtf8(ecmaVm, GetName().c_str()))); - object->Set(ecmaVm, StringRef::NewFromUtf8(ecmaVm, "params"), Local(params)); + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); return object; } -std::unique_ptr Resumed::Create(const EcmaVM *ecmaVm, [[maybe_unused]] const Local ¶ms) +std::unique_ptr Resumed::ToJson() const { - return std::make_unique(); -} + std::unique_ptr result = PtJson::CreateObject(); -Local Resumed::ToObject(const EcmaVM *ecmaVm) -{ - Local params = NewObject(ecmaVm); - - Local object = NewObject(ecmaVm); - object->Set(ecmaVm, - StringRef::NewFromUtf8(ecmaVm, "method"), - Local(StringRef::NewFromUtf8(ecmaVm, GetName().c_str()))); - object->Set(ecmaVm, StringRef::NewFromUtf8(ecmaVm, "params"), Local(params)); + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); return object; } -std::unique_ptr ScriptFailedToParse::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr ScriptFailedToParse::ToJson() const { - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "ScriptFailedToParse::Create params is nullptr"; - return nullptr; - } - CString error; - auto scriptEvent = std::make_unique(); - - Local result = Local(params)->Get(ecmaVm, StringRef::NewFromUtf8(ecmaVm, "scriptId")); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->scriptId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptId' should a String;"; - } - } else { - error += "should contain 'scriptId';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "url"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->url_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'url' should a String;"; - } - } else { - error += "should contain 'url';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "startLine"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->startLine_ = static_cast(Local(result)->Value()); - } else { - error += "'startLine' should a Number;"; - } - } else { - error += "should contain 'startLine';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "startColumn"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->startColumn_ = static_cast(Local(result)->Value()); - } else { - error += "'startColumn' should a Number;"; - } - } else { - error += "should contain 'startColumn';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endLine"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->endLine_ = static_cast(Local(result)->Value()); - } else { - error += "'endLine' should a Number;"; - } - } else { - error += "should contain 'endLine';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endColumn"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->endColumn_ = static_cast(Local(result)->Value()); - } else { - error += "'endColumn' should a Number;"; - } - } else { - error += "should contain 'endColumn';"; - } - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "executionContextId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->executionContextId_ = static_cast(Local(result)->Value()); - } else { - error += "'executionContextId' should a Number;"; - } - } else { - error += "should contain 'executionContextId';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "hash"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->hash_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'hash' should a String;"; - } - } else { - error += "should contain 'hash';"; - } - result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "executionContextAuxData"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - scriptEvent->execContextAuxData_ = Local(result); - } else { - error += "'executionContextAuxData' should a Object;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "sourceMapURL"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->sourceMapUrl_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'sourceMapURL' should a String;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "hasSourceURL"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - scriptEvent->hasSourceUrl_ = result->IsTrue(); - } else { - error += "'hasSourceURL' should a Boolean;"; - } + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("scriptId", std::to_string(scriptId_).c_str()); + result->Add("url", url_.c_str()); + result->Add("startLine", startLine_); + result->Add("startColumn", startColumn_); + result->Add("endLine", endLine_); + result->Add("endColumn", endColumn_); + result->Add("executionContextId", executionContextId_); + result->Add("hash", hash_.c_str()); + if (sourceMapUrl_) { + result->Add("sourceMapURL", sourceMapUrl_->c_str()); } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "isModule"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - scriptEvent->isModule_ = result->IsTrue(); - } else { - error += "'isModule' should a Boolean;"; - } + if (hasSourceUrl_) { + result->Add("hasSourceURL", hasSourceUrl_.value()); } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "length"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->length_ = static_cast(Local(result)->Value()); - } else { - error += "'length' should a Number;"; - } + if (isModule_) { + result->Add("isModule", isModule_.value()); } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "codeOffset"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->codeOffset_ = static_cast(Local(result)->Value()); - } else { - error += "'codeOffset' should a Number;"; - } + if (length_) { + result->Add("length", length_.value()); } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptLanguage"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->scriptLanguage_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptLanguage' should a String;"; - } + if (codeOffset_) { + result->Add("codeOffset", codeOffset_.value()); } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "embedderName"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->embedderName_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'embedderName' should a String;"; - } + if (scriptLanguage_) { + result->Add("scriptLanguage", scriptLanguage_->c_str()); } - if (!error.empty()) { - LOG(ERROR, DEBUGGER) << "ScriptFailedToParse::Create " << error; - return nullptr; + if (embedderName_) { + result->Add("embedderName", embedderName_->c_str()); } - return scriptEvent; + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); + + return object; } -Local ScriptFailedToParse::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr ScriptParsed::ToJson() const { - Local params = NewObject(ecmaVm); - - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptId")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptId_.c_str()))); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "url")), - Local(StringRef::NewFromUtf8(ecmaVm, url_.c_str()))); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "startLine")), - IntegerRef::New(ecmaVm, startLine_)); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "startColumn")), - IntegerRef::New(ecmaVm, startColumn_)); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endLine")), - IntegerRef::New(ecmaVm, endLine_)); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endColumn")), - IntegerRef::New(ecmaVm, endColumn_)); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "executionContextId")), - IntegerRef::New(ecmaVm, executionContextId_)); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "hash")), - Local(StringRef::NewFromUtf8(ecmaVm, hash_.c_str()))); - if (execContextAuxData_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "executionContextAuxData")), - Local(execContextAuxData_.value())); + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("scriptId", std::to_string(scriptId_).c_str()); + result->Add("url", url_.c_str()); + result->Add("startLine", startLine_); + result->Add("startColumn", startColumn_); + result->Add("endLine", endLine_); + result->Add("endColumn", endColumn_); + result->Add("executionContextId", executionContextId_); + result->Add("hash", hash_.c_str()); + if (isLiveEdit_) { + result->Add("isLiveEdit", isLiveEdit_.value()); } if (sourceMapUrl_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "sourceMapURL")), - Local(StringRef::NewFromUtf8(ecmaVm, sourceMapUrl_->c_str()))); + result->Add("sourceMapURL", sourceMapUrl_->c_str()); } if (hasSourceUrl_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "hasSourceURL")), - BooleanRef::New(ecmaVm, hasSourceUrl_.value())); + result->Add("hasSourceURL", hasSourceUrl_.value()); } if (isModule_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "isModule")), - BooleanRef::New(ecmaVm, isModule_.value())); + result->Add("isModule", isModule_.value()); } if (length_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "length")), - IntegerRef::New(ecmaVm, length_.value())); + result->Add("length", length_.value()); } if (codeOffset_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "codeOffset")), - IntegerRef::New(ecmaVm, codeOffset_.value())); + result->Add("codeOffset", codeOffset_.value()); } if (scriptLanguage_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptLanguage")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptLanguage_->c_str()))); + result->Add("scriptLanguage", scriptLanguage_->c_str()); } if (embedderName_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "embedderName")), - Local(StringRef::NewFromUtf8(ecmaVm, embedderName_->c_str()))); + result->Add("embedderName", embedderName_->c_str()); } - Local object = NewObject(ecmaVm); - object->Set(ecmaVm, - StringRef::NewFromUtf8(ecmaVm, "method"), - Local(StringRef::NewFromUtf8(ecmaVm, GetName().c_str()))); - object->Set(ecmaVm, StringRef::NewFromUtf8(ecmaVm, "params"), Local(params)); + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); return object; } -std::unique_ptr ScriptParsed::Create(const std::unique_ptr &script) +#ifdef SUPPORT_PROFILER_CDP +std::unique_ptr AddHeapSnapshotChunk::ToJson() const { - std::unique_ptr scriptParsed = std::make_unique(); - scriptParsed->SetScriptId(script->GetScriptId()) - .SetUrl(script->GetUrl()) - .SetStartLine(0) - .SetStartColumn(0) - .SetEndLine(script->GetEndLine()) - .SetEndColumn(0) - .SetExecutionContextId(0) - .SetHash(script->GetHash()); - return scriptParsed; + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("chunk", chunk_.c_str()); + + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); + + return object; } -std::unique_ptr ScriptParsed::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr ConsoleProfileFinished::ToJson() const { - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "ScriptParsed::Create params is nullptr"; - return nullptr; - } - CString error; - auto scriptEvent = std::make_unique(); - - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->scriptId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptId' should a String;"; - } - } else { - error += "should contain 'scriptId';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "url"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->url_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'url' should a String;"; - } - } else { - error += "should contain 'url';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "startLine"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->startLine_ = static_cast(Local(result)->Value()); - } else { - error += "'startLine' should a Number;"; - } - } else { - error += "should contain 'startLine';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "startColumn"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->startColumn_ = static_cast(Local(result)->Value()); - } else { - error += "'startColumn' should a Number;"; - } - } else { - error += "should contain 'startColumn';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endLine"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->endLine_ = static_cast(Local(result)->Value()); - } else { - error += "'endLine' should a Number;"; - } - } else { - error += "should contain 'endLine';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endColumn"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->endColumn_ = static_cast(Local(result)->Value()); - } else { - error += "'endColumn' should a Number;"; - } - } else { - error += "should contain 'endColumn';"; - } - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "executionContextId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->executionContextId_ = static_cast(Local(result)->Value()); - } else { - error += "'executionContextId' should a Number;"; - } - } else { - error += "should contain 'executionContextId';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "hash"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->hash_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'hash' should a String;"; - } - } else { - error += "should contain 'hash';"; - } - result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "executionContextAuxData"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - scriptEvent->execContextAuxData_ = Local(result); - } else { - error += "'executionContextAuxData' should a Object;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "isLiveEdit"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - scriptEvent->isLiveEdit_ = result->IsTrue(); - } else { - error += "'isLiveEdit' should a Boolean;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "sourceMapURL"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->sourceMapUrl_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'sourceMapURL' should a String;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "hasSourceURL"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - scriptEvent->hasSourceUrl_ = result->IsTrue(); - } else { - error += "'hasSourceURL' should a Boolean;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "isModule"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - scriptEvent->isModule_ = result->IsTrue(); - } else { - error += "'isModule' should a Boolean;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "length"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->length_ = static_cast(Local(result)->Value()); - } else { - error += "'length' should a Number;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "codeOffset"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptEvent->codeOffset_ = static_cast(Local(result)->Value()); - } else { - error += "'codeOffset' should a Number;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptLanguage"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->scriptLanguage_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptLanguage' should a String;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "embedderName"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scriptEvent->embedderName_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'embedderName' should a String;"; - } - } - if (!error.empty()) { - LOG(ERROR, DEBUGGER) << "ScriptParsed::Create " << error; - return nullptr; + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("id", id_.c_str()); + ASSERT(location_ != nullptr); + result->Add("location", location_->ToJson()); + ASSERT(profile_ != nullptr); + result->Add("profile", profile_->ToJson()); + if (title_) { + result->Add("title", title_->c_str()); } - return scriptEvent; + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); + + return object; } -Local ScriptParsed::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr ConsoleProfileStarted::ToJson() const { - Local params = NewObject(ecmaVm); - - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptId")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptId_.c_str()))); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "url")), - Local(StringRef::NewFromUtf8(ecmaVm, url_.c_str()))); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "startLine")), - IntegerRef::New(ecmaVm, startLine_)); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "startColumn")), - IntegerRef::New(ecmaVm, startColumn_)); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endLine")), - IntegerRef::New(ecmaVm, endLine_)); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endColumn")), - IntegerRef::New(ecmaVm, endColumn_)); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "executionContextId")), - IntegerRef::New(ecmaVm, executionContextId_)); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "hash")), - Local(StringRef::NewFromUtf8(ecmaVm, hash_.c_str()))); - if (execContextAuxData_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "executionContextAuxData")), - Local(execContextAuxData_.value())); - } - if (isLiveEdit_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "isLiveEdit")), - BooleanRef::New(ecmaVm, isLiveEdit_.value())); - } - if (sourceMapUrl_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "sourceMapURL")), - Local(StringRef::NewFromUtf8(ecmaVm, sourceMapUrl_->c_str()))); - } - if (hasSourceUrl_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "hasSourceURL")), - BooleanRef::New(ecmaVm, hasSourceUrl_.value())); - } - if (isModule_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "isModule")), - BooleanRef::New(ecmaVm, isModule_.value())); - } - if (length_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "length")), - IntegerRef::New(ecmaVm, length_.value())); + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("id", id_.c_str()); + ASSERT(location_ != nullptr); + result->Add("location", location_->ToJson()); + if (title_) { + result->Add("title", title_->c_str()); } - if (codeOffset_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "codeOffset")), - IntegerRef::New(ecmaVm, codeOffset_.value())); + + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); + + return object; +} + +std::unique_ptr PreciseCoverageDeltaUpdate::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("timestamp", timestamp_); + result->Add("occasion", occasion_.c_str()); + std::unique_ptr array = PtJson::CreateArray(); + size_t len = result_.size(); + for (size_t i = 0; i < len; i++) { + ASSERT(result_[i] != nullptr); + std::unique_ptr res = result_[i]->ToJson(); + array->Push(res); } - if (scriptLanguage_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptLanguage")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptLanguage_->c_str()))); + result->Add("result", array); + + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); + + return object; +} + +std::unique_ptr HeapStatsUpdate::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + std::unique_ptr array = PtJson::CreateArray(); + size_t len = statsUpdate_.size(); + for (size_t i = 0; i < len; i++) { + array->Push(statsUpdate_[i]); } - if (embedderName_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "embedderName")), - Local(StringRef::NewFromUtf8(ecmaVm, embedderName_->c_str()))); + result->Add("statsUpdate", array); + + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); + + return object; +} + +std::unique_ptr LastSeenObjectId::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("lastSeenObjectId", lastSeenObjectId_); + result->Add("timestamp", timestamp_); + + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); + + return object; +} + +std::unique_ptr ReportHeapSnapshotProgress::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("done", done_); + result->Add("total", total_); + if (finished_) { + result->Add("finished", finished_.value()); } - Local object = NewObject(ecmaVm); - object->Set(ecmaVm, - StringRef::NewFromUtf8(ecmaVm, "method"), - Local(StringRef::NewFromUtf8(ecmaVm, GetName().c_str()))); - object->Set(ecmaVm, StringRef::NewFromUtf8(ecmaVm, "params"), Local(params)); + + std::unique_ptr object = PtJson::CreateObject(); + object->Add("method", GetName().c_str()); + object->Add("params", result); return object; } +#endif } // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/base/pt_events.h b/ecmascript/tooling/base/pt_events.h index 204db2534d2cd24aa31889b2f2ad8057664dcb53..d5a29910dd840bbcefae515600a2715d39114aec 100644 --- a/ecmascript/tooling/base/pt_events.h +++ b/ecmascript/tooling/base/pt_events.h @@ -23,17 +23,13 @@ #include "ecmascript/tooling/base/pt_script.h" #include "ecmascript/tooling/base/pt_types.h" #include "ecmascript/tooling/dispatcher.h" -#include "ecmascript/mem/c_containers.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::EcmaVM; - class PtBaseEvents : public PtBaseTypes { public: PtBaseEvents() = default; ~PtBaseEvents() override = default; - Local ToObject(const EcmaVM *ecmaVm) override = 0; - virtual CString GetName() = 0; + virtual std::string GetName() const = 0; private: NO_COPY_SEMANTIC(PtBaseEvents); @@ -44,10 +40,9 @@ class BreakpointResolved final : public PtBaseEvents { public: BreakpointResolved() = default; ~BreakpointResolved() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; - CString GetName() override + std::string GetName() const override { return "Debugger.breakpointResolved"; } @@ -86,26 +81,25 @@ class Paused final : public PtBaseEvents { public: Paused() = default; ~Paused() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; - CString GetName() override + std::string GetName() const override { return "Debugger.paused"; } - const CVector> *GetCallFrames() const + const std::vector> *GetCallFrames() const { return &callFrames_; } - Paused &SetCallFrames(CVector> call_frames) + Paused &SetCallFrames(std::vector> callFrames) { - callFrames_ = std::move(call_frames); + callFrames_ = std::move(callFrames); return *this; } - CString GetReason() const + const std::string &GetReason() const { return reason_; } @@ -116,7 +110,7 @@ public: return *this; } - static CString GetReasonString(PauseReason reason) + static std::string GetReasonString(PauseReason reason) { switch (reason) { case AMBIGUOUS: { @@ -181,12 +175,12 @@ public: return data_.has_value(); } - CVector GetHitBreakpoints() const + std::vector GetHitBreakpoints() const { - return hitBreakpoints_.value_or(CVector()); + return hitBreakpoints_.value_or(std::vector()); } - Paused &SetHitBreakpoints(CVector hitBreakpoints) + Paused &SetHitBreakpoints(std::vector hitBreakpoints) { hitBreakpoints_ = std::move(hitBreakpoints); return *this; @@ -201,20 +195,19 @@ private: NO_COPY_SEMANTIC(Paused); NO_MOVE_SEMANTIC(Paused); - CVector> callFrames_ {}; - CString reason_ {}; + std::vector> callFrames_ {}; + std::string reason_ {}; std::optional> data_ {}; - std::optional> hitBreakpoints_ {}; + std::optional> hitBreakpoints_ {}; }; class Resumed final : public PtBaseEvents { public: Resumed() = default; ~Resumed() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; - CString GetName() override + std::string GetName() const override { return "Debugger.resumed"; } @@ -228,10 +221,9 @@ class ScriptFailedToParse final : public PtBaseEvents { public: ScriptFailedToParse() = default; ~ScriptFailedToParse() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; - CString GetName() override + std::string GetName() const override { return "Debugger.scriptFailedToParse"; } @@ -241,18 +233,18 @@ public: return scriptId_; } - ScriptFailedToParse &SetScriptId(const ScriptId &scriptId) + ScriptFailedToParse &SetScriptId(ScriptId scriptId) { scriptId_ = scriptId; return *this; } - CString GetUrl() const + const std::string &GetUrl() const { return url_; } - ScriptFailedToParse &SetUrl(const CString &url) + ScriptFailedToParse &SetUrl(const std::string &url) { url_ = url; return *this; @@ -313,12 +305,12 @@ public: return *this; } - CString GetHash() const + const std::string &GetHash() const { return hash_; } - ScriptFailedToParse &SetHash(const CString &hash) + ScriptFailedToParse &SetHash(const std::string &hash) { hash_ = hash; return *this; @@ -329,7 +321,7 @@ public: return execContextAuxData_.value_or(Local()); } - ScriptFailedToParse &SetExecutionContextAuxData(const Local &execContextAuxData) + ScriptFailedToParse &SetExecutionContextAuxData(Local execContextAuxData) { execContextAuxData_ = execContextAuxData; return *this; @@ -340,18 +332,19 @@ public: return execContextAuxData_.has_value(); } - CString GetSourceMapURL() const + const std::string &GetSourceMapURL() const { - return sourceMapUrl_.value_or(""); + ASSERT(HasSourceMapUrl()); + return sourceMapUrl_.value(); } - ScriptFailedToParse &SetSourceMapURL(const CString &sourceMapUrl) + ScriptFailedToParse &SetSourceMapURL(const std::string &sourceMapUrl) { sourceMapUrl_ = sourceMapUrl; return *this; } - bool HasSourceMapURL() const + bool HasSourceMapUrl() const { return sourceMapUrl_.has_value(); } @@ -420,12 +413,13 @@ public: return codeOffset_.has_value(); } - CString GetScriptLanguage() const + const std::string &GetScriptLanguage() const { - return scriptLanguage_.value_or(""); + ASSERT(HasScriptLanguage()); + return scriptLanguage_.value(); } - ScriptFailedToParse &SetScriptLanguage(const CString &scriptLanguage) + ScriptFailedToParse &SetScriptLanguage(const std::string &scriptLanguage) { scriptLanguage_ = scriptLanguage; return *this; @@ -436,12 +430,13 @@ public: return scriptLanguage_.has_value(); } - CString GetEmbedderName() const + const std::string &GetEmbedderName() const { - return embedderName_.value_or(""); + ASSERT(HasEmbedderName()); + return embedderName_.value(); } - ScriptFailedToParse &SetEmbedderName(const CString &embedderName) + ScriptFailedToParse &SetEmbedderName(const std::string &embedderName) { embedderName_ = embedderName; return *this; @@ -456,33 +451,31 @@ private: NO_COPY_SEMANTIC(ScriptFailedToParse); NO_MOVE_SEMANTIC(ScriptFailedToParse); - ScriptId scriptId_ {}; - CString url_ {}; + ScriptId scriptId_ {0}; + std::string url_ {}; int32_t startLine_ {0}; int32_t startColumn_ {0}; int32_t endLine_ {0}; int32_t endColumn_ {0}; ExecutionContextId executionContextId_ {0}; - CString hash_ {}; + std::string hash_ {}; std::optional> execContextAuxData_ {}; - std::optional sourceMapUrl_ {}; + std::optional sourceMapUrl_ {}; std::optional hasSourceUrl_ {}; std::optional isModule_ {}; std::optional length_ {}; std::optional codeOffset_ {}; - std::optional scriptLanguage_ {}; - std::optional embedderName_ {}; + std::optional scriptLanguage_ {}; + std::optional embedderName_ {}; }; class ScriptParsed final : public PtBaseEvents { public: ScriptParsed() = default; ~ScriptParsed() override = default; - static std::unique_ptr Create(const std::unique_ptr &script); - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; - CString GetName() override + std::string GetName() const override { return "Debugger.scriptParsed"; } @@ -492,57 +485,57 @@ public: return scriptId_; } - ScriptParsed &SetScriptId(const ScriptId &scriptId) + ScriptParsed &SetScriptId(ScriptId scriptId) { scriptId_ = scriptId; return *this; } - CString GetUrl() const + const std::string &GetUrl() const { return url_; } - ScriptParsed &SetUrl(const CString &url) + ScriptParsed &SetUrl(const std::string &url) { url_ = url; return *this; } - size_t GetStartLine() const + int32_t GetStartLine() const { return startLine_; } - ScriptParsed &SetStartLine(size_t startLine) + ScriptParsed &SetStartLine(int32_t startLine) { startLine_ = startLine; return *this; } - size_t GetStartColumn() const + int32_t GetStartColumn() const { return startColumn_; } - ScriptParsed &SetStartColumn(size_t startColumn) + ScriptParsed &SetStartColumn(int32_t startColumn) { startColumn_ = startColumn; return *this; } - size_t GetEndLine() const + int32_t GetEndLine() const { return endLine_; } - ScriptParsed &SetEndLine(size_t endLine) + ScriptParsed &SetEndLine(int32_t endLine) { endLine_ = endLine; return *this; } - size_t GetEndColumn() const + int32_t GetEndColumn() const { return endColumn_; } @@ -564,12 +557,12 @@ public: return *this; } - CString GetHash() const + const std::string &GetHash() const { return hash_; } - ScriptParsed &SetHash(const CString &hash) + ScriptParsed &SetHash(const std::string &hash) { hash_ = hash; return *this; @@ -596,7 +589,7 @@ public: return execContextAuxData_.value_or(Local()); } - ScriptParsed &SetExecutionContextAuxData(const Local &execContextAuxData) + ScriptParsed &SetExecutionContextAuxData(Local execContextAuxData) { execContextAuxData_ = execContextAuxData; return *this; @@ -607,18 +600,19 @@ public: return execContextAuxData_.has_value(); } - CString GetSourceMapURL() const + const std::string &GetSourceMapURL() const { - return sourceMapUrl_.value_or(""); + ASSERT(HasSourceMapUrl()); + return sourceMapUrl_.value(); } - ScriptParsed &SetSourceMapURL(const CString &sourceMapUrl) + ScriptParsed &SetSourceMapURL(const std::string &sourceMapUrl) { sourceMapUrl_ = sourceMapUrl; return *this; } - bool HasSourceMapURL() const + bool HasSourceMapUrl() const { return sourceMapUrl_.has_value(); } @@ -655,12 +649,12 @@ public: return isModule_.has_value(); } - uint32_t GetLength() const + int32_t GetLength() const { return length_.value_or(0); } - ScriptParsed &SetLength(uint32_t length) + ScriptParsed &SetLength(int32_t length) { length_ = length; return *this; @@ -671,12 +665,12 @@ public: return length_.has_value(); } - uint32_t GetCodeOffset() const + int32_t GetCodeOffset() const { return codeOffset_.value_or(0); } - ScriptParsed &SetCodeOffset(uint32_t codeOffset) + ScriptParsed &SetCodeOffset(int32_t codeOffset) { codeOffset_ = codeOffset; return *this; @@ -687,12 +681,13 @@ public: return codeOffset_.has_value(); } - CString GetScriptLanguage() const + const std::string &GetScriptLanguage() const { - return scriptLanguage_.value_or(""); + ASSERT(HasScriptLanguage()); + return scriptLanguage_.value(); } - ScriptParsed &SetScriptLanguage(const CString &scriptLanguage) + ScriptParsed &SetScriptLanguage(const std::string &scriptLanguage) { scriptLanguage_ = scriptLanguage; return *this; @@ -703,12 +698,13 @@ public: return scriptLanguage_.has_value(); } - CString GetEmbedderName() const + const std::string &GetEmbedderName() const { - return embedderName_.value_or(""); + ASSERT(HasEmbedderName()); + return embedderName_.value(); } - ScriptParsed &SetEmbedderName(const CString &embedderName) + ScriptParsed &SetEmbedderName(const std::string &embedderName) { embedderName_ = embedderName; return *this; @@ -723,23 +719,351 @@ private: NO_COPY_SEMANTIC(ScriptParsed); NO_MOVE_SEMANTIC(ScriptParsed); - ScriptId scriptId_ {}; - CString url_ {}; - size_t startLine_ {0}; - size_t startColumn_ {0}; - size_t endLine_ {0}; - size_t endColumn_ {0}; + ScriptId scriptId_ {0}; + std::string url_ {}; + int32_t startLine_ {0}; + int32_t startColumn_ {0}; + int32_t endLine_ {0}; + int32_t endColumn_ {0}; ExecutionContextId executionContextId_ {0}; - CString hash_ {}; + std::string hash_ {}; std::optional> execContextAuxData_ {}; std::optional isLiveEdit_ {}; - std::optional sourceMapUrl_ {}; + std::optional sourceMapUrl_ {}; std::optional hasSourceUrl_ {}; std::optional isModule_ {}; - std::optional length_ {}; - std::optional codeOffset_ {}; - std::optional scriptLanguage_ {}; - std::optional embedderName_ {}; + std::optional length_ {}; + std::optional codeOffset_ {}; + std::optional scriptLanguage_ {}; + std::optional embedderName_ {}; +}; + +#ifdef SUPPORT_PROFILER_CDP +class AddHeapSnapshotChunk final : public PtBaseEvents { +public: + AddHeapSnapshotChunk() = default; + ~AddHeapSnapshotChunk() override = default; + std::unique_ptr ToJson() const override; + + std::string GetName() const override + { + return "HeapProfiler.addHeapSnapshotChunk"; + } + + std::string &GetChunk() + { + return chunk_; + } + +private: + NO_COPY_SEMANTIC(AddHeapSnapshotChunk); + NO_MOVE_SEMANTIC(AddHeapSnapshotChunk); + + std::string chunk_ {}; +}; + +class ConsoleProfileFinished final : public PtBaseEvents { +public: + ConsoleProfileFinished() = default; + ~ConsoleProfileFinished() override = default; + std::unique_ptr ToJson() const override; + std::string GetName() const override + { + return "Profile.ConsoleProfileFinished"; + } + + const std::string &GetId() const + { + return id_; + } + + ConsoleProfileFinished &SetId(const std::string &id) + { + id_ = id; + return *this; + } + + Location *GetLocation() const + { + return location_.get(); + } + + ConsoleProfileFinished &SetLocation(std::unique_ptr location) + { + location_ = std::move(location); + return *this; + } + + Profile *GetProfile() const + { + return profile_.get(); + } + + ConsoleProfileFinished &SetProfile(std::unique_ptr profile) + { + profile_ = std::move(profile); + return *this; + } + + const std::string &GetTitle() const + { + ASSERT(HasTitle()); + return title_.value(); + } + + ConsoleProfileFinished &SetTitle(const std::string &title) + { + title_ = title; + return *this; + } + + bool HasTitle() const + { + return title_.has_value(); + } + +private: + NO_COPY_SEMANTIC(ConsoleProfileFinished); + NO_MOVE_SEMANTIC(ConsoleProfileFinished); + + std::string id_ {}; + std::unique_ptr location_ {nullptr}; + std::unique_ptr profile_ {nullptr}; + std::optional title_ {}; }; + +class ConsoleProfileStarted final : public PtBaseEvents { +public: + ConsoleProfileStarted() = default; + ~ConsoleProfileStarted() override = default; + std::unique_ptr ToJson() const override; + std::string GetName() const override + { + return "Profile.ConsoleProfileStarted"; + } + + const std::string &GetId() const + { + return id_; + } + + ConsoleProfileStarted &SetId(const std::string &id) + { + id_ = id; + return *this; + } + + Location *GetLocation() const + { + return location_.get(); + } + + ConsoleProfileStarted &SetLocation(std::unique_ptr location) + { + location_ = std::move(location); + return *this; + } + + const std::string &GetTitle() const + { + ASSERT(HasTitle()); + return title_.value(); + } + + ConsoleProfileStarted &SetTitle(const std::string &title) + { + title_ = title; + return *this; + } + + bool HasTitle() const + { + return title_.has_value(); + } + +private: + NO_COPY_SEMANTIC(ConsoleProfileStarted); + NO_MOVE_SEMANTIC(ConsoleProfileStarted); + + std::string id_ {}; + std::unique_ptr location_ {nullptr}; + std::optional title_ {}; +}; + +class PreciseCoverageDeltaUpdate final : public PtBaseEvents { +public: + PreciseCoverageDeltaUpdate() = default; + ~PreciseCoverageDeltaUpdate() override = default; + std::unique_ptr ToJson() const override; + std::string GetName() const override + { + return "Profile.PreciseCoverageDeltaUpdate"; + } + + int64_t GetTimestamp() const + { + return timestamp_; + } + + PreciseCoverageDeltaUpdate &SetTimestamp(int64_t timestamp) + { + timestamp_ = timestamp; + return *this; + } + + const std::string &GetOccasion() const + { + return occasion_; + } + + PreciseCoverageDeltaUpdate &SetOccasion(const std::string &occasion) + { + occasion_ = occasion; + return *this; + } + + const std::vector> *GetResult() const + { + return &result_; + } + + PreciseCoverageDeltaUpdate &SetResult(std::vector> result) + { + result_ = std::move(result); + return *this; + } + +private: + NO_COPY_SEMANTIC(PreciseCoverageDeltaUpdate); + NO_MOVE_SEMANTIC(PreciseCoverageDeltaUpdate); + + int64_t timestamp_ {0}; + std::string occasion_ {}; + std::vector> result_ {}; +}; + +class HeapStatsUpdate final : public PtBaseEvents { +public: + HeapStatsUpdate() = default; + ~HeapStatsUpdate() override = default; + std::unique_ptr ToJson() const override; + + std::string GetName() const override + { + return "HeapProfiler.heapStatsUpdate"; + } + + const std::vector *GetStatsUpdate() const + { + return &statsUpdate_; + } + + HeapStatsUpdate &SetStatsUpdate(std::vector statsUpdate) + { + statsUpdate_ = std::move(statsUpdate); + return *this; + } + +private: + NO_COPY_SEMANTIC(HeapStatsUpdate); + NO_MOVE_SEMANTIC(HeapStatsUpdate); + + std::vector statsUpdate_ {}; +}; + +class LastSeenObjectId final : public PtBaseEvents { +public: + LastSeenObjectId() = default; + ~LastSeenObjectId() override = default; + std::unique_ptr ToJson() const override; + + std::string GetName() const override + { + return "HeapProfiler.lastSeenObjectId"; + } + + int32_t GetLastSeenObjectId() const + { + return lastSeenObjectId_; + } + + LastSeenObjectId &SetLastSeenObjectId(int32_t lastSeenObjectId) + { + lastSeenObjectId_ = lastSeenObjectId; + return *this; + } + + int64_t GetTimestamp() const + { + return timestamp_; + } + + LastSeenObjectId &SetTimestamp(int64_t timestamp) + { + timestamp_ = timestamp; + return *this; + } + +private: + NO_COPY_SEMANTIC(LastSeenObjectId); + NO_MOVE_SEMANTIC(LastSeenObjectId); + + int32_t lastSeenObjectId_ {}; + int64_t timestamp_ {}; +}; + +class ReportHeapSnapshotProgress final : public PtBaseEvents { +public: + ReportHeapSnapshotProgress() = default; + ~ReportHeapSnapshotProgress() override = default; + std::unique_ptr ToJson() const override; + + std::string GetName() const override + { + return "HeapProfiler.reportHeapSnapshotProgress"; + } + + int32_t GetDone() const + { + return done_; + } + + ReportHeapSnapshotProgress &SetDone(int32_t done) + { + done_ = done; + return *this; + } + + int32_t GetTotal() const + { + return total_; + } + + ReportHeapSnapshotProgress &SetTotal(int32_t total) + { + total_ = total; + return *this; + } + + bool GetFinished() const + { + return finished_.value_or(false); + } + + ReportHeapSnapshotProgress &SetFinished(bool finished) + { + finished_ = finished; + return *this; + } + +private: + NO_COPY_SEMANTIC(ReportHeapSnapshotProgress); + NO_MOVE_SEMANTIC(ReportHeapSnapshotProgress); + + int32_t done_ {}; + int32_t total_ {}; + std::optional finished_ {}; +}; +#endif } // namespace panda::ecmascript::tooling #endif diff --git a/ecmascript/tooling/base/pt_json.cpp b/ecmascript/tooling/base/pt_json.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2943e98b2b65a797e1783f7c3c853b13fc1d9ce8 --- /dev/null +++ b/ecmascript/tooling/base/pt_json.cpp @@ -0,0 +1,432 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/tooling/base/pt_json.h" + +#include "libpandabase/macros.h" + +namespace panda::ecmascript::tooling { +std::unique_ptr PtJson::CreateObject() +{ + return std::make_unique(cJSON_CreateObject()); +} + +std::unique_ptr PtJson::CreateArray() +{ + return std::make_unique(cJSON_CreateArray()); +} + +void PtJson::ReleaseRoot() +{ + if (object_ != nullptr) { + cJSON_Delete(object_); + object_ = nullptr; + } +} + +std::unique_ptr PtJson::Parse(const std::string &data) +{ + cJSON *value = cJSON_ParseWithOpts(data.c_str(), nullptr, true); + return std::make_unique(value); +} + +std::string PtJson::Stringify() const +{ + if (object_ == nullptr) { + return ""; + } + + char *str = cJSON_PrintUnformatted(object_); + if (str == nullptr) { + return ""; + } + + std::string result(str); + cJSON_free(str); + return result; +} + +bool PtJson::Add(const char *key, bool value) const +{ + ASSERT(key != nullptr && !Contains(key)); + + cJSON *node = cJSON_CreateBool(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToObject(object_, key, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Add(const char *key, int32_t value) const +{ + return Add(key, static_cast(value)); +} + +bool PtJson::Add(const char *key, int64_t value) const +{ + return Add(key, static_cast(value)); +} + +bool PtJson::Add(const char *key, double value) const +{ + ASSERT(key != nullptr && !Contains(key)); + + cJSON *node = cJSON_CreateNumber(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToObject(object_, key, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Add(const char *key, const char *value) const +{ + ASSERT(key != nullptr && !Contains(key)); + + cJSON *node = cJSON_CreateString(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToObject(object_, key, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Add(const char *key, const std::unique_ptr &value) const +{ + ASSERT(key != nullptr && !Contains(key)); + + cJSON *node = value->GetJson(); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToObject(object_, key, node); + if (ret == 0) { + return false; + } + + return true; +} + +bool PtJson::Push(bool value) const +{ + cJSON *node = cJSON_CreateBool(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToArray(object_, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Push(int32_t value) const +{ + return Push(static_cast(value)); +} + +bool PtJson::Push(int64_t value) const +{ + return Push(static_cast(value)); +} + +bool PtJson::Push(double value) const +{ + cJSON *node = cJSON_CreateNumber(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToArray(object_, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Push(const char *value) const +{ + cJSON *node = cJSON_CreateString(value); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToArray(object_, node); + if (ret == 0) { + cJSON_Delete(node); + return false; + } + + return true; +} + +bool PtJson::Push(const std::unique_ptr &value) const +{ + if (value == nullptr) { + return false; + } + + cJSON *node = value->GetJson(); + if (node == nullptr) { + return false; + } + + cJSON_bool ret = cJSON_AddItemToArray(object_, node); + if (ret == 0) { + return false; + } + + return true; +} + +bool PtJson::Remove(const char *key) const +{ + ASSERT(key != nullptr && Contains(key)); + + cJSON_DeleteItemFromObject(object_, key); + return true; +} + +bool PtJson::Contains(const char *key) const +{ + cJSON *node = cJSON_GetObjectItemCaseSensitive(object_, key); + return node != nullptr; +} + +std::string PtJson::GetKey() const +{ + if (object_ == nullptr || object_->string == nullptr) { + return ""; + } + + return std::string(object_->string); +} + +cJSON *PtJson::GetJson() const +{ + return object_; +} + +bool PtJson::IsBool() const +{ + return cJSON_IsBool(object_) != 0; +} + +bool PtJson::IsNumber() const +{ + return cJSON_IsNumber(object_) != 0; +} + +bool PtJson::IsString() const +{ + return cJSON_IsString(object_) != 0; +} + +bool PtJson::IsObject() const +{ + return cJSON_IsObject(object_) != 0; +} + +bool PtJson::IsArray() const +{ + return cJSON_IsArray(object_) != 0; +} + +bool PtJson::IsNull() const +{ + return cJSON_IsNull(object_) != 0; +} + +bool PtJson::GetBool(bool defaultValue) const +{ + if (!IsBool()) { + return defaultValue; + } + + return cJSON_IsTrue(object_) != 0; +} + +int32_t PtJson::GetInt(int32_t defaultValue) const +{ + if (!IsNumber()) { + return defaultValue; + } + + return static_cast(object_->valuedouble); +} + +int64_t PtJson::GetInt64(int64_t defaultValue) const +{ + if (!IsNumber()) { + return defaultValue; + } + + return static_cast(object_->valuedouble); +} + +double PtJson::GetDouble(double defaultValue) const +{ + if (!IsNumber()) { + return defaultValue; + } + + return object_->valuedouble; +} + +std::string PtJson::GetString() const +{ + if (!IsString()) { + return ""; + } + + return std::string(object_->valuestring); +} + +int32_t PtJson::GetSize() const +{ + return cJSON_GetArraySize(object_); +} + +std::unique_ptr PtJson::Get(int32_t index) const +{ + return std::make_unique(cJSON_GetArrayItem(object_, index)); +} + +Result PtJson::GetBool(const char *key, bool *value) const +{ + cJSON *item = cJSON_GetObjectItem(object_, key); + if (item == nullptr) { + return Result::NOT_EXIST; + } + if (cJSON_IsBool(item) == 0) { + return Result::TYPE_ERROR; + } + + *value = cJSON_IsTrue(item) != 0; + return Result::SUCCESS; +} + +Result PtJson::GetInt(const char *key, int32_t *value) const +{ + double result; + Result ret = GetDouble(key, &result); + if (ret == Result::SUCCESS) { + *value = static_cast(result); + } + return ret; +} + +Result PtJson::GetInt64(const char *key, int64_t *value) const +{ + double result; + Result ret = GetDouble(key, &result); + if (ret == Result::SUCCESS) { + *value = static_cast(result); + } + return ret; +} + +Result PtJson::GetDouble(const char *key, double *value) const +{ + cJSON *item = cJSON_GetObjectItem(object_, key); + if (item == nullptr) { + return Result::NOT_EXIST; + } + if (cJSON_IsNumber(item) == 0) { + return Result::TYPE_ERROR; + } + + *value = item->valuedouble; + return Result::SUCCESS; +} + +Result PtJson::GetString(const char *key, std::string *value) const +{ + cJSON *item = cJSON_GetObjectItem(object_, key); + if (item == nullptr) { + return Result::NOT_EXIST; + } + if (cJSON_IsString(item) == 0) { + return Result::TYPE_ERROR; + } + + *value = item->valuestring; + return Result::SUCCESS; +} + +Result PtJson::GetObject(const char *key, std::unique_ptr *value) const +{ + cJSON *item = cJSON_GetObjectItem(object_, key); + if (item == nullptr) { + return Result::NOT_EXIST; + } + if (cJSON_IsObject(item) == 0) { + return Result::TYPE_ERROR; + } + + *value = std::make_unique(item); + return Result::SUCCESS; +} + +Result PtJson::GetArray(const char *key, std::unique_ptr *value) const +{ + cJSON *item = cJSON_GetObjectItem(object_, key); + if (item == nullptr) { + return Result::NOT_EXIST; + } + if (cJSON_IsArray(item) == 0) { + return Result::TYPE_ERROR; + } + + *value = std::make_unique(item); + return Result::SUCCESS; +} + +Result PtJson::GetAny(const char *key, std::unique_ptr *value) const +{ + cJSON *item = cJSON_GetObjectItem(object_, key); + if (item == nullptr) { + return Result::NOT_EXIST; + } + + *value = std::make_unique(item); + return Result::SUCCESS; +} +} // namespace panda::ecmascript diff --git a/ecmascript/tooling/base/pt_json.h b/ecmascript/tooling/base/pt_json.h new file mode 100644 index 0000000000000000000000000000000000000000..88f6cc15f19749e4fb7c8b7c084effa11aa964ad --- /dev/null +++ b/ecmascript/tooling/base/pt_json.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_TOOLING_BASE_PT_JSON_H +#define ECMASCRIPT_TOOLING_BASE_PT_JSON_H + +#include +#include + +#include "cJSON.h" + +namespace panda::ecmascript::tooling { +enum class Result : uint8_t { + SUCCESS, + NOT_EXIST, + TYPE_ERROR, +}; + +class PtJson { +public: + PtJson() = default; + explicit PtJson(cJSON *object) : object_(object) {} + ~PtJson() = default; + + // Create empty json object + static std::unique_ptr CreateObject(); + static std::unique_ptr CreateArray(); + + // Release cJSON object memory + void ReleaseRoot(); + + // String parse to json + static std::unique_ptr Parse(const std::string &data); + + // To string + std::string Stringify() const; + + // Add Json child + bool Add(const char *key, bool value) const; + bool Add(const char *key, int32_t value) const; + bool Add(const char *key, int64_t value) const; + bool Add(const char *key, double value) const; + bool Add(const char *key, const char *value) const; + bool Add(const char *key, const std::unique_ptr &value) const; + + // Push back to array + bool Push(bool value) const; + bool Push(int32_t value) const; + bool Push(int64_t value) const; + bool Push(double value) const; + bool Push(const char *value) const; + bool Push(const std::unique_ptr &value) const; + + // Remove Json child + bool Remove(const char *key) const; + + bool Contains(const char *key) const; + + std::string GetKey() const; + + cJSON *GetJson() const; + + // Type check + bool IsBool() const; + bool IsNumber() const; + bool IsString() const; + bool IsObject() const; + bool IsArray() const; + bool IsNull() const; + + // Object accessor + bool GetBool(bool defaultValue = false) const; + int32_t GetInt(int32_t defaultValue = 0) const; + int64_t GetInt64(int64_t defaultValue = 0) const; + double GetDouble(double defaultValue = 0.0) const; + std::string GetString() const; + + // Array accessor + int32_t GetSize() const; + std::unique_ptr Get(int32_t index) const; + + // Child item accessor + Result GetBool(const char *key, bool *value) const; + Result GetInt(const char *key, int32_t *value) const; + Result GetInt64(const char *key, int64_t *value) const; + Result GetDouble(const char *key, double *value) const; + Result GetString(const char *key, std::string *value) const; + Result GetObject(const char *key, std::unique_ptr *value) const; + Result GetArray(const char *key, std::unique_ptr *value) const; + Result GetAny(const char *key, std::unique_ptr *value) const; + +private: + cJSON *object_ = nullptr; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_TOOLING_BASE_PT_JSON_H diff --git a/ecmascript/tooling/base/pt_params.cpp b/ecmascript/tooling/base/pt_params.cpp index bd22a90ca77e44e7434a620dee412c22204252c2..4bfe284cd8ef5ea51057b36a0fcfece48640c5b9 100644 --- a/ecmascript/tooling/base/pt_params.cpp +++ b/ecmascript/tooling/base/pt_params.cpp @@ -16,25 +16,20 @@ #include "ecmascript/tooling/base/pt_params.h" namespace panda::ecmascript::tooling { -std::unique_ptr EnableParams::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr EnableParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "maxScriptsCacheSize"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - paramsObject->maxScriptsCacheSize_ = Local(result)->Value(); - } else { - error += "'maxScriptsCacheSize' should be a Number;"; - } + double maxScriptsCacheSize; + ret = params.GetDouble("maxScriptsCacheSize", &maxScriptsCacheSize); + if (ret == Result::SUCCESS) { + paramsObject->maxScriptsCacheSize_ = maxScriptsCacheSize; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'maxScriptsCacheSize';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "EnableParams::Create " << error; return nullptr; @@ -43,71 +38,67 @@ std::unique_ptr EnableParams::Create(const EcmaVM *ecmaVm, const L return paramsObject; } -std::unique_ptr EvaluateOnCallFrameParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr EvaluateOnCallFrameParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "EvaluateOnCallFrameParams::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "callFrameId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->callFrameId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'callframeid' should be a String;"; - } + std::string callFrameId; + ret = params.GetString("callFrameId", &callFrameId); + if (ret == Result::SUCCESS) { + paramsObject->callFrameId_ = std::stoi(callFrameId); } else { - error += "should contain 'callframeid';"; + error += "Unknown 'callFrameId';"; } - - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "expression"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->expression_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'expression' should be a String;"; - } + std::string expression; + ret = params.GetString("expression", &expression); + if (ret == Result::SUCCESS) { + paramsObject->expression_ = std::move(expression); } else { - error += "should contain 'expression';"; - } - - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "objectGroup"))); - if (!result.IsEmpty() && result->IsString()) { - paramsObject->objectGroup_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } - - result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "includeCommandLineAPI"))); - if (!result.IsEmpty() && result->IsBoolean()) { - paramsObject->includeCommandLineApi_ = result->IsTrue(); - } - - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "silent"))); - if (!result.IsEmpty() && result->IsBoolean()) { - paramsObject->silent_ = result->IsTrue(); - } - - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "returnByValue"))); - if (!result.IsEmpty() && result->IsBoolean()) { - paramsObject->returnByValue_ = result->IsTrue(); - } - - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "generatePreview"))); - if (!result.IsEmpty() && result->IsBoolean()) { - paramsObject->generatePreview_ = result->IsTrue(); - } - - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "throwOnSideEffect"))); - if (!result.IsEmpty() && result->IsBoolean()) { - paramsObject->throwOnSideEffect_ = result->IsTrue(); + error += "Unknown 'expression';"; + } + std::string objectGroup; + ret = params.GetString("objectGroup", &objectGroup); + if (ret == Result::SUCCESS) { + paramsObject->objectGroup_ = std::move(objectGroup); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'objectGroup';"; + } + bool includeCommandLineAPI; + ret = params.GetBool("includeCommandLineAPI", &includeCommandLineAPI); + if (ret == Result::SUCCESS) { + paramsObject->includeCommandLineAPI_ = includeCommandLineAPI; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'includeCommandLineAPI';"; + } + bool silent; + ret = params.GetBool("silent", &silent); + if (ret == Result::SUCCESS) { + paramsObject->silent_ = silent; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'silent';"; + } + bool returnByValue; + ret = params.GetBool("returnByValue", &returnByValue); + if (ret == Result::SUCCESS) { + paramsObject->returnByValue_ = returnByValue; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'returnByValue';"; + } + bool generatePreview; + ret = params.GetBool("generatePreview", &generatePreview); + if (ret == Result::SUCCESS) { + paramsObject->generatePreview_ = generatePreview; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'generatePreview';"; + } + bool throwOnSideEffect; + ret = params.GetBool("throwOnSideEffect", &throwOnSideEffect); + if (ret == Result::SUCCESS) { + paramsObject->throwOnSideEffect_ = throwOnSideEffect; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'throwOnSideEffect';"; } if (!error.empty()) { @@ -117,55 +108,44 @@ std::unique_ptr EvaluateOnCallFrameParams::Create(con return paramsObject; } -std::unique_ptr GetPossibleBreakpointsParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr GetPossibleBreakpointsParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "start"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = Location::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'start' format error;"; - } else { - paramsObject->start_ = std::move(obj); - } + std::unique_ptr start; + ret = params.GetObject("start", &start); + if (ret == Result::SUCCESS) { + std::unique_ptr location = Location::Create(*start); + if (location == nullptr) { + error += "Unknown 'start';"; } else { - error += "'start' should be an Object;"; + paramsObject->start_ = std::move(location); } } else { - error += "should contain 'start';"; + error += "Unknown 'start';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "end"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = Location::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'end' format error;"; - } else { - paramsObject->end_ = std::move(obj); - } + std::unique_ptr end; + ret = params.GetObject("start", &end); + if (ret == Result::SUCCESS) { + std::unique_ptr location = Location::Create(*end); + if (location == nullptr) { + error += "Unknown 'end';"; } else { - error += "'end' should be an Object;"; + paramsObject->end_ = std::move(location); } + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'end';"; } - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "restrictToFunction"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->restrictToFunction_ = result->IsTrue(); - } else { - error += "'restrictToFunction' should be a Boolean;"; - } + bool restrictToFunction; + ret = params.GetBool("restrictToFunction", &restrictToFunction); + if (ret == Result::SUCCESS) { + paramsObject->restrictToFunction_ = restrictToFunction; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'restrictToFunction';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "GetPossibleBreakpointsParams::Create " << error; return nullptr; @@ -174,28 +154,20 @@ std::unique_ptr GetPossibleBreakpointsParams::Crea return paramsObject; } -std::unique_ptr GetScriptSourceParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr GetScriptSourceParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->scriptId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptId' should be a String;"; - } + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + paramsObject->scriptId_ = std::stoi(scriptId); } else { - error += "should contain 'scriptId';"; + error += "Unknown 'scriptId';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "GetScriptSourceParams::Create " << error; return nullptr; @@ -204,28 +176,20 @@ std::unique_ptr GetScriptSourceParams::Create(const EcmaV return paramsObject; } -std::unique_ptr RemoveBreakpointParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr RemoveBreakpointParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "breakpointId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->breakpointId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'breakpointId' should be a String;"; - } + std::string breakpointId; + ret = params.GetString("breakpointId", &breakpointId); + if (ret == Result::SUCCESS) { + paramsObject->breakpointId_ = std::move(breakpointId); } else { - error += "should contain 'breakpointId';"; + error += "Unknown 'breakpointId';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "RemoveBreakpointParams::Create " << error; return nullptr; @@ -234,25 +198,20 @@ std::unique_ptr RemoveBreakpointParams::Create(const Ecm return paramsObject; } -std::unique_ptr ResumeParams::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr ResumeParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "terminateOnResume"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->terminateOnResume_ = result->IsTrue(); - } else { - error += "'terminateOnResume' should be a Boolean;"; - } + bool terminateOnResume; + ret = params.GetBool("terminateOnResume", &terminateOnResume); + if (ret == Result::SUCCESS) { + paramsObject->terminateOnResume_ = terminateOnResume; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'terminateOnResume';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "ResumeParams::Create " << error; return nullptr; @@ -261,28 +220,20 @@ std::unique_ptr ResumeParams::Create(const EcmaVM *ecmaVm, const L return paramsObject; } -std::unique_ptr SetAsyncCallStackDepthParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr SetAsyncCallStackDepthParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "maxDepth"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - paramsObject->maxDepth_ = static_cast(Local(result)->Value()); - } else { - error += "'maxDepth' should be a Number;"; - } + int32_t maxDepth; + ret = params.GetInt("maxDepth", &maxDepth); + if (ret == Result::SUCCESS) { + paramsObject->maxDepth_ = maxDepth; } else { - error += "should contain 'maxDepth';"; + error += "Unknown 'maxDepth';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "SetAsyncCallStackDepthParams::Create " << error; return nullptr; @@ -291,40 +242,28 @@ std::unique_ptr SetAsyncCallStackDepthParams::Crea return paramsObject; } -std::unique_ptr SetBlackboxPatternsParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr SetBlackboxPatternsParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); - - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "patterns"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsArray(ecmaVm)) { - Local array = Local(result); - uint32_t len = array->Length(ecmaVm); - Local key = JSValueRef::Undefined(ecmaVm); - for (uint32_t i = 0; i < len; i++) { - key = IntegerRef::New(ecmaVm, i); - Local value = Local(array)->Get(ecmaVm, key->ToString(ecmaVm)); - if (value->IsString()) { - paramsObject->patterns_.emplace_back( - DebuggerApi::ConvertToString(StringRef::Cast(*value)->ToString())); - } else { - error += "'patterns' items should be a String;"; - } + std::string error; + Result ret; + + std::unique_ptr patterns; + ret = params.GetArray("patterns", &patterns); + if (ret == Result::SUCCESS) { + int32_t len = patterns->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr item = patterns->Get(i); + if (item->IsString()) { + paramsObject->patterns_.emplace_back(item->GetString()); + } else { + error += "'patterns' items should be a String;"; } - } else { - error += "'patterns' should be an Array;"; } } else { - error += "should contain 'patterns';"; + error += "Unknown 'patterns';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "SetBlackboxPatternsParams::Create " << error; return nullptr; @@ -333,67 +272,53 @@ std::unique_ptr SetBlackboxPatternsParams::Create(con return paramsObject; } -std::unique_ptr SetBreakpointByUrlParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr SetBreakpointByUrlParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - paramsObject->line_ = static_cast(Local(result)->Value()); - } else { - error += "'lineNumber' should be a Number;"; - } + int32_t lineNumber; + ret = params.GetInt("lineNumber", &lineNumber); + if (ret == Result::SUCCESS) { + paramsObject->lineNumber_ = lineNumber; } else { - error += "should contain 'lineNumber';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "url"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->url_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'url' should be a String;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "urlRegex"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->urlRegex_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'urlRegex' should be a String;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptHash"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->scriptHash_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptHash' should be a String;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - paramsObject->column_ = static_cast(Local(result)->Value()); - } else { - error += "'columnNumber' should be a Number;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "condition"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->condition_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'condition' should be a String;"; - } + error += "Unknown 'lineNumber';"; + } + std::string url; + ret = params.GetString("url", &url); + if (ret == Result::SUCCESS) { + paramsObject->url_ = std::move(url); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'url';"; + } + std::string urlRegex; + ret = params.GetString("urlRegex", &urlRegex); + if (ret == Result::SUCCESS) { + paramsObject->urlRegex_ = std::move(urlRegex); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'urlRegex';"; + } + std::string scriptHash; + ret = params.GetString("scriptHash", &scriptHash); + if (ret == Result::SUCCESS) { + paramsObject->scriptHash_ = std::move(scriptHash); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'scriptHash';"; + } + int32_t columnNumber; + ret = params.GetInt("columnNumber", &columnNumber); + if (ret == Result::SUCCESS) { + paramsObject->columnNumber_ = columnNumber; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'columnNumber';"; + } + std::string condition; + ret = params.GetString("condition", &condition); + if (ret == Result::SUCCESS) { + paramsObject->condition_ = std::move(condition); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'condition';"; } if (!error.empty()) { LOG(ERROR, DEBUGGER) << "SetBreakpointByUrlParams::Create " << error; @@ -403,30 +328,20 @@ std::unique_ptr SetBreakpointByUrlParams::Create(const return paramsObject; } -std::unique_ptr SetPauseOnExceptionsParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr SetPauseOnExceptionsParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "state"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - if (!paramsObject->StoreState(DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()))) { - error += "'state' is invalid;"; - } - } else { - error += "'state' should be a String;"; - } + std::string state; + ret = params.GetString("state", &state); + if (ret == Result::SUCCESS) { + paramsObject->StoreState(state); } else { - error += "should contain 'state';"; + error += "Unknown 'state';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "SetPauseOnExceptionsParams::Create " << error; return nullptr; @@ -435,49 +350,35 @@ std::unique_ptr SetPauseOnExceptionsParams::Create(c return paramsObject; } -std::unique_ptr StepIntoParams::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr StepIntoParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); - - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "breakOnAsyncCall"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->breakOnAsyncCall_ = result->IsTrue(); - } else { - error += "'terminateOnResume' should be a Boolean;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "skipList"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsArray(ecmaVm)) { - Local array = Local(result); - uint32_t len = array->Length(ecmaVm); - Local key = JSValueRef::Undefined(ecmaVm); - for (uint32_t i = 0; i < len; i++) { - key = IntegerRef::New(ecmaVm, i); - Local value = Local(array)->Get(ecmaVm, key->ToString(ecmaVm)); - if (value->IsObject()) { - std::unique_ptr obj = LocationRange::Create(ecmaVm, value); - if (obj != nullptr) { - paramsObject->skipList_->emplace_back(std::move(obj)); - } else { - error += "'skipList' items LocationRange is invalid;"; - } - } else { - error += "'skipList' items should be an Object;"; - } + std::string error; + Result ret; + + bool breakOnAsyncCall; + ret = params.GetBool("breakOnAsyncCall", &breakOnAsyncCall); + if (ret == Result::SUCCESS) { + paramsObject->breakOnAsyncCall_ = breakOnAsyncCall; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'breakOnAsyncCall';"; + } + std::unique_ptr skipList; + ret = params.GetArray("skipList", &skipList); + if (ret == Result::SUCCESS) { + int32_t len = skipList->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr obj = LocationRange::Create(*skipList->Get(i)); + if (obj == nullptr) { + error += "'skipList' items LocationRange is invalid;"; + } else { + paramsObject->skipList_->emplace_back(std::move(obj)); } - } else { - error += "'skipList' should be an Array;"; } + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'skipList';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "StepIntoParams::Create " << error; return nullptr; @@ -486,41 +387,28 @@ std::unique_ptr StepIntoParams::Create(const EcmaVM *ecmaVm, con return paramsObject; } -std::unique_ptr StepOverParams::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr StepOverParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); - - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "skipList"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsArray(ecmaVm)) { - Local array = Local(result); - uint32_t len = array->Length(ecmaVm); - Local key = JSValueRef::Undefined(ecmaVm); - for (uint32_t i = 0; i < len; i++) { - key = IntegerRef::New(ecmaVm, i); - Local value = Local(array)->Get(ecmaVm, key->ToString(ecmaVm)); - if (value->IsObject()) { - std::unique_ptr obj = LocationRange::Create(ecmaVm, value); - if (obj != nullptr) { - paramsObject->skipList_->emplace_back(std::move(obj)); - } else { - error += "'skipList' items LocationRange is invaild;"; - } - } else { - error += "'skipList' items should be an Object;"; - } + std::string error; + Result ret; + + std::unique_ptr skipList; + ret = params.GetArray("skipList", &skipList); + if (ret == Result::SUCCESS) { + int32_t len = skipList->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr obj = LocationRange::Create(*skipList->Get(i)); + if (obj == nullptr) { + error += "'skipList' items LocationRange is invalid;"; + } else { + paramsObject->skipList_->emplace_back(std::move(obj)); } - } else { - error += "'skipList' should be an Array;"; } + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'skipList';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "StepOverParams::Create " << error; return nullptr; @@ -529,52 +417,39 @@ std::unique_ptr StepOverParams::Create(const EcmaVM *ecmaVm, con return paramsObject; } -std::unique_ptr GetPropertiesParams::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr GetPropertiesParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "GetPropertiesParams::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "objectId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->objectId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'objectId' should be a String;"; - } + std::string objectId; + ret = params.GetString("objectId", &objectId); + if (ret == Result::SUCCESS) { + paramsObject->objectId_ = std::stoi(objectId); } else { - error += "should contain 'objectId';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "ownProperties"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->ownProperties_ = result->IsTrue(); - } else { - error += "'ownProperties' should be a Boolean;"; - } - } - result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "accessorPropertiesOnly"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->accessorPropertiesOnly_ = result->IsTrue(); - } else { - error += "'accessorPropertiesOnly' should be a Boolean;"; - } - } - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "generatePreview"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->generatePreview_ = result->IsTrue(); - } else { - error += "'generatePreview' should be a Boolean;"; - } + error += "Unknown 'objectId';"; + } + bool ownProperties; + ret = params.GetBool("ownProperties", &ownProperties); + if (ret == Result::SUCCESS) { + paramsObject->ownProperties_ = ownProperties; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'ownProperties';"; + } + bool accessorPropertiesOnly; + ret = params.GetBool("accessorPropertiesOnly", &accessorPropertiesOnly); + if (ret == Result::SUCCESS) { + paramsObject->accessorPropertiesOnly_ = accessorPropertiesOnly; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'accessorPropertiesOnly';"; + } + bool generatePreview; + ret = params.GetBool("generatePreview", &generatePreview); + if (ret == Result::SUCCESS) { + paramsObject->generatePreview_ = generatePreview; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'generatePreview';"; } if (!error.empty()) { LOG(ERROR, DEBUGGER) << "GetPropertiesParams::Create " << error; @@ -584,139 +459,110 @@ std::unique_ptr GetPropertiesParams::Create(const EcmaVM *e return paramsObject; } -std::unique_ptr CallFunctionOnParams::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr CallFunctionOnParams::Create(const PtJson ¶ms) { - ASSERT(ecmaVm); - if (params.IsEmpty()) { - LOG(ERROR, DEBUGGER) << "CallFunctionOnParams::Create params is nullptr"; - return nullptr; - } - CString error; auto paramsObject = std::make_unique(); + std::string error; + Result ret; // paramsObject->functionDeclaration_ - Local result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "functionDeclaration"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->functionDeclaration_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'functionDeclaration' should be a String;"; - } + std::string functionDeclaration; + ret = params.GetString("functionDeclaration", &functionDeclaration); + if (ret == Result::SUCCESS) { + paramsObject->functionDeclaration_ = std::move(functionDeclaration); } else { - error += "should contain 'functionDeclaration';"; + error += "Unknown 'functionDeclaration';"; } // paramsObject->objectId_ - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "objectId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->objectId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'objectId' should be a String;"; - } + std::string objectId; + ret = params.GetString("objectId", &objectId); + if (ret == Result::SUCCESS) { + paramsObject->objectId_ = std::stoi(objectId); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'objectId';"; } // paramsObject->arguments_ - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "arguments"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsArray(ecmaVm)) { - Local array = Local(result); - uint32_t len = array->Length(ecmaVm); - Local key = JSValueRef::Undefined(ecmaVm); - for (uint32_t i = 0; i < len; i++) { - key = IntegerRef::New(ecmaVm, i); - Local value = Local(array)->Get(ecmaVm, key->ToString(ecmaVm)); - if (value->IsObject()) { - std::unique_ptr obj = CallArgument::Create(ecmaVm, value); - if (obj != nullptr) { - paramsObject->arguments_->emplace_back(std::move(obj)); - } else { - error += "'arguments' items CallArgument is invaild;"; - } - } else { - error += "'arguments' items should be an Object;"; - } + std::unique_ptr arguments; + ret = params.GetArray("arguments", &arguments); + if (ret == Result::SUCCESS) { + int32_t len = arguments->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr obj = CallArgument::Create(*arguments->Get(i)); + if (obj == nullptr) { + error += "'arguments' items CallArgument is invaild;"; + } else { + paramsObject->arguments_->emplace_back(std::move(obj)); } - } else { - error += "'arguments' should be an Array;"; } + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'arguments';"; } // paramsObject->silent_ - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "silent"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->silent_ = result->IsTrue(); - } else { - error += "'silent' should be a Boolean;"; - } + bool silent; + ret = params.GetBool("silent", &silent); + if (ret == Result::SUCCESS) { + paramsObject->silent_ = silent; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'silent';"; } // paramsObject->returnByValue_ - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "returnByValue"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->returnByValue_ = result->IsTrue(); - } else { - error += "'returnByValue' should be a Boolean;"; - } + bool returnByValue; + ret = params.GetBool("returnByValue", &returnByValue); + if (ret == Result::SUCCESS) { + paramsObject->returnByValue_ = returnByValue; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'returnByValue';"; } // paramsObject->generatePreview_ - result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "generatePreview"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->generatePreview_ = result->IsTrue(); - } else { - error += "'generatePreview' should be a Boolean;"; - } + bool generatePreview; + ret = params.GetBool("generatePreview", &generatePreview); + if (ret == Result::SUCCESS) { + paramsObject->generatePreview_ = generatePreview; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'generatePreview';"; } // paramsObject->userGesture_ - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "userGesture"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->userGesture_ = result->IsTrue(); - } else { - error += "'userGesture' should be a Boolean;"; - } + bool userGesture; + ret = params.GetBool("userGesture", &userGesture); + if (ret == Result::SUCCESS) { + paramsObject->userGesture_ = userGesture; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'userGesture';"; } // paramsObject->awaitPromise_ - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "awaitPromise"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->awaitPromise_ = result->IsTrue(); - } else { - error += "'awaitPromise' should be a Boolean;"; - } + bool awaitPromise; + ret = params.GetBool("awaitPromise", &awaitPromise); + if (ret == Result::SUCCESS) { + paramsObject->awaitPromise_ = awaitPromise; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'awaitPromise';"; } // paramsObject->executionContextId_ - result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "executionContextId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - paramsObject->executionContextId_ = static_cast(Local(result)->Value()); - } else { - error += "'executionContextId' should be a Number;"; - } + int32_t executionContextId; + ret = params.GetInt("executionContextId", &executionContextId); + if (ret == Result::SUCCESS) { + paramsObject->executionContextId_ = executionContextId; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'executionContextId';"; } // paramsObject->objectGroup_ - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "objectGroup"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - paramsObject->objectGroup_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'objectGroup' should be a String;"; - } + std::string objectGroup; + ret = params.GetString("objectGroup", &objectGroup); + if (ret == Result::SUCCESS) { + paramsObject->objectGroup_ = std::move(objectGroup); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'objectGroup';"; } // paramsObject->throwOnSideEffect_ - result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "throwOnSideEffect"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - paramsObject->throwOnSideEffect_ = result->IsTrue(); - } else { - error += "'throwOnSideEffect' should be a Boolean;"; - } + bool throwOnSideEffect; + ret = params.GetBool("throwOnSideEffect", &throwOnSideEffect); + if (ret == Result::SUCCESS) { + paramsObject->throwOnSideEffect_ = throwOnSideEffect; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'throwOnSideEffect';"; } - // Check whether the CString(error) is empty. + + // Check whether the error is empty. if (!error.empty()) { LOG(ERROR, DEBUGGER) << "CallFunctionOnParams::Create " << error; return nullptr; @@ -724,4 +570,214 @@ std::unique_ptr CallFunctionOnParams::Create(const EcmaVM return paramsObject; } + +#ifdef SUPPORT_PROFILER_CDP +std::unique_ptr StartSamplingParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + int32_t samplingInterval; + ret = params.GetInt("samplingInterval", &samplingInterval); + if (ret == Result::SUCCESS) { + paramsObject->samplingInterval_ = samplingInterval; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'samplingInterval';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "StartSamplingParams::Create " << error; + return nullptr; + } + return paramsObject; +} + +std::unique_ptr StartTrackingHeapObjectsParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + bool trackAllocations; + ret = params.GetBool("trackAllocations", &trackAllocations); + if (ret == Result::SUCCESS) { + paramsObject->trackAllocations_ = trackAllocations; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'trackAllocations';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "StartTrackingHeapObjectsParams::Create " << error; + return nullptr; + } + return paramsObject; +} + +std::unique_ptr StopTrackingHeapObjectsParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + bool reportProgress; + ret = params.GetBool("reportProgress", &reportProgress); + if (ret == Result::SUCCESS) { + paramsObject->reportProgress_ = reportProgress; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'reportProgress';"; + } + + bool treatGlobalObjectsAsRoots; + ret = params.GetBool("treatGlobalObjectsAsRoots", &treatGlobalObjectsAsRoots); + if (ret == Result::SUCCESS) { + paramsObject->treatGlobalObjectsAsRoots_ = treatGlobalObjectsAsRoots; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'treatGlobalObjectsAsRoots';"; + } + + bool captureNumericValue; + ret = params.GetBool("captureNumericValue", &captureNumericValue); + if (ret == Result::SUCCESS) { + paramsObject->captureNumericValue_ = captureNumericValue; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'captureNumericValue';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "StopTrackingHeapObjectsParams::Create " << error; + return nullptr; + } + return paramsObject; +} + +std::unique_ptr AddInspectedHeapObjectParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + std::string heapObjectId; + ret = params.GetString("heapObjectId", &heapObjectId); + if (ret == Result::SUCCESS) { + paramsObject->heapObjectId_ = std::stoi(heapObjectId); + } else { + error += "Unknown 'heapObjectId';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "AddInspectedHeapObjectParams::Create " << error; + return nullptr; + } + return paramsObject; +} + +std::unique_ptr GetHeapObjectIdParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + std::string objectId; + ret = params.GetString("objectId", &objectId); + if (ret == Result::SUCCESS) { + paramsObject->objectId_ = std::stoi(objectId); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'objectId';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "GetHeapObjectIdParams::Create " << error; + return nullptr; + } + return paramsObject; +} + +std::unique_ptr GetObjectByHeapObjectIdParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + std::string objectId; + ret = params.GetString("objectId", &objectId); + if (ret == Result::SUCCESS) { + paramsObject->objectId_ = std::stoi(objectId); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'objectId';"; + } + + std::string objectGroup; + ret = params.GetString("objectGroup", &objectGroup); + if (ret == Result::SUCCESS) { + paramsObject->objectGroup_ = std::move(objectGroup); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'objectGroup';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "GetObjectByHeapObjectIdParams::Create " << error; + return nullptr; + } + return paramsObject; +} + +std::unique_ptr StartPreciseCoverageParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + bool callCount; + ret = params.GetBool("callCount", &callCount); + if (ret == Result::SUCCESS) { + paramsObject->callCount_ = callCount; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'callCount';"; + } + + bool detailed; + ret = params.GetBool("detailed", &detailed); + if (ret == Result::SUCCESS) { + paramsObject->detailed_ = detailed; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'detailed';"; + } + + bool allowTriggeredUpdates; + ret = params.GetBool("allowTriggeredUpdates", &allowTriggeredUpdates); + if (ret == Result::SUCCESS) { + paramsObject->allowTriggeredUpdates_ = allowTriggeredUpdates; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'allowTriggeredUpdates';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "StartPreciseCoverageParams::Create " << error; + return nullptr; + } + return paramsObject; +} + +std::unique_ptr SetSamplingIntervalParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::string error; + Result ret; + + int32_t interval; + ret = params.GetInt("interval", &interval); + if (ret == Result::SUCCESS) { + paramsObject->interval_ = interval; + } else { + error += "Unknown 'interval';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "SetSamplingIntervalParams::Create " << error; + return nullptr; + } + return paramsObject; +} +#endif } // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/base/pt_params.h b/ecmascript/tooling/base/pt_params.h index c60fe2f8d9e86f483ebacdc896a2778367e4a548..dc2ae0536e2ea4a1fb3aa3e4bcce44bee77eab99 100644 --- a/ecmascript/tooling/base/pt_params.h +++ b/ecmascript/tooling/base/pt_params.h @@ -23,8 +23,10 @@ class PtBaseParams : public PtBaseTypes { public: PtBaseParams() = default; ~PtBaseParams() override = default; - - virtual Local ToObject(const EcmaVM *ecmaVm) override = 0; + std::unique_ptr ToJson() const override + { + UNREACHABLE(); + } private: NO_COPY_SEMANTIC(PtBaseParams); @@ -36,11 +38,7 @@ public: EnableParams() = default; ~EnableParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); double GetMaxScriptsCacheSize() const { @@ -56,7 +54,7 @@ private: NO_COPY_SEMANTIC(EnableParams); NO_MOVE_SEMANTIC(EnableParams); - std::optional maxScriptsCacheSize_ {0}; + std::optional maxScriptsCacheSize_ {}; }; class EvaluateOnCallFrameParams : public PtBaseParams { @@ -64,18 +62,14 @@ public: EvaluateOnCallFrameParams() = default; ~EvaluateOnCallFrameParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); - CString GetCallFrameId() + CallFrameId GetCallFrameId() const { return callFrameId_; } - CString GetExpression() + const std::string &GetExpression() const { return expression_; } @@ -84,10 +78,10 @@ private: NO_COPY_SEMANTIC(EvaluateOnCallFrameParams); NO_MOVE_SEMANTIC(EvaluateOnCallFrameParams); - CString callFrameId_ {}; - CString expression_ {}; - std::optional objectGroup_ {}; - std::optional includeCommandLineApi_ {}; + CallFrameId callFrameId_ {}; + std::string expression_ {}; + std::optional objectGroup_ {}; + std::optional includeCommandLineAPI_ {}; std::optional silent_ {}; std::optional returnByValue_ {}; std::optional generatePreview_ {}; @@ -99,11 +93,7 @@ public: GetPossibleBreakpointsParams() = default; ~GetPossibleBreakpointsParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); Location *GetStart() const { @@ -147,11 +137,7 @@ public: GetScriptSourceParams() = default; ~GetScriptSourceParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); ScriptId GetScriptId() const { @@ -162,7 +148,7 @@ private: NO_COPY_SEMANTIC(GetScriptSourceParams); NO_MOVE_SEMANTIC(GetScriptSourceParams); - ScriptId scriptId_ {}; + ScriptId scriptId_ {0}; }; class RemoveBreakpointParams : public PtBaseParams { @@ -170,11 +156,7 @@ public: RemoveBreakpointParams() = default; ~RemoveBreakpointParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); BreakpointId GetBreakpointId() const { @@ -193,11 +175,7 @@ public: ResumeParams() = default; ~ResumeParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); bool GetTerminateOnResume() const { @@ -221,13 +199,9 @@ public: SetAsyncCallStackDepthParams() = default; ~SetAsyncCallStackDepthParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); - uint32_t GetMaxDepth() const + int32_t GetMaxDepth() const { return maxDepth_; } @@ -236,20 +210,16 @@ private: NO_COPY_SEMANTIC(SetAsyncCallStackDepthParams); NO_MOVE_SEMANTIC(SetAsyncCallStackDepthParams); - uint32_t maxDepth_ {0}; + int32_t maxDepth_ {0}; }; class SetBlackboxPatternsParams : public PtBaseParams { public: SetBlackboxPatternsParams() = default; ~SetBlackboxPatternsParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); - CList GetPatterns() const + std::list GetPatterns() const { return patterns_; } @@ -258,7 +228,7 @@ private: NO_COPY_SEMANTIC(SetBlackboxPatternsParams); NO_MOVE_SEMANTIC(SetBlackboxPatternsParams); - CList patterns_ {}; + std::list patterns_ {}; }; class SetBreakpointByUrlParams : public PtBaseParams { @@ -266,20 +236,17 @@ public: SetBreakpointByUrlParams() = default; ~SetBreakpointByUrlParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); int32_t GetLine() const { - return line_; + return lineNumber_; } - CString GetUrl() const + const std::string &GetUrl() const { - return url_.value_or(""); + ASSERT(HasUrl()); + return url_.value(); } bool HasUrl() const @@ -287,9 +254,10 @@ public: return url_.has_value(); } - CString GetUrlRegex() const + const std::string &GetUrlRegex() const { - return urlRegex_.value_or(""); + ASSERT(HasUrlRegex()); + return urlRegex_.value(); } bool HasUrlRegex() const @@ -297,9 +265,10 @@ public: return urlRegex_.has_value(); } - CString GetScriptHash() const + const std::string &GetScriptHash() const { - return scriptHash_.value_or(""); + ASSERT(HasScriptHash()); + return scriptHash_.value(); } bool HasScriptHash() const @@ -309,17 +278,18 @@ public: int32_t GetColumn() const { - return column_.value_or(0); + return columnNumber_.value_or(0); } bool HasColumn() const { - return column_.has_value(); + return columnNumber_.has_value(); } - CString GetCondition() const + const std::string &GetCondition() const { - return condition_.value_or(""); + ASSERT(HasCondition()); + return condition_.value(); } bool HasCondition() const @@ -331,12 +301,12 @@ private: NO_COPY_SEMANTIC(SetBreakpointByUrlParams); NO_MOVE_SEMANTIC(SetBreakpointByUrlParams); - size_t line_ {0}; - std::optional url_ {}; - std::optional urlRegex_ {}; - std::optional scriptHash_ {}; - std::optional column_ {0}; - std::optional condition_ {}; + int32_t lineNumber_ {0}; + std::optional url_ {}; + std::optional urlRegex_ {}; + std::optional scriptHash_ {}; + std::optional columnNumber_ {0}; + std::optional condition_ {}; }; enum class PauseOnExceptionsState : uint8_t { NONE, UNCAUGHT, ALL }; @@ -345,18 +315,14 @@ class SetPauseOnExceptionsParams : public PtBaseParams { public: SetPauseOnExceptionsParams() = default; ~SetPauseOnExceptionsParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); PauseOnExceptionsState GetState() const { return state_; } - bool StoreState(const CString &state) + bool StoreState(const std::string &state) { if (state == "none") { state_ = PauseOnExceptionsState::NONE; @@ -385,11 +351,7 @@ public: StepIntoParams() = default; ~StepIntoParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); bool GetBreakOnAsyncCall() const { @@ -401,7 +363,7 @@ public: return breakOnAsyncCall_.has_value(); } - const CList> *GetSkipList() const + const std::list> *GetSkipList() const { if (!skipList_) { return nullptr; @@ -419,7 +381,7 @@ private: NO_MOVE_SEMANTIC(StepIntoParams); std::optional breakOnAsyncCall_ {}; - std::optional>> skipList_ {}; + std::optional>> skipList_ {}; }; class StepOverParams : public PtBaseParams { @@ -427,13 +389,9 @@ public: StepOverParams() = default; ~StepOverParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); - const CList> *GetSkipList() const + const std::list> *GetSkipList() const { if (!skipList_) { return nullptr; @@ -450,7 +408,7 @@ private: NO_COPY_SEMANTIC(StepOverParams); NO_MOVE_SEMANTIC(StepOverParams); - std::optional>> skipList_ {}; + std::optional>> skipList_ {}; }; class GetPropertiesParams : public PtBaseParams { @@ -458,11 +416,7 @@ public: GetPropertiesParams() = default; ~GetPropertiesParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); RemoteObjectId GetObjectId() const { @@ -514,20 +468,16 @@ public: CallFunctionOnParams() = default; ~CallFunctionOnParams() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject([[maybe_unused]] const EcmaVM *ecmaVm) override - { - return Local(); - } + static std::unique_ptr Create(const PtJson ¶ms); - CString GetFunctionDeclaration() + const std::string &GetFunctionDeclaration() { return functionDeclaration_; } RemoteObjectId GetObjectId() const { - return objectId_.value(); + return objectId_.value_or(-1); } CallFunctionOnParams &SetObjectId(RemoteObjectId objectId) @@ -541,7 +491,7 @@ public: return objectId_.has_value(); } - const CVector> *GetArguments() const + const std::vector> *GetArguments() const { if (!arguments_) { return nullptr; @@ -620,9 +570,10 @@ public: return executionContextId_.has_value(); } - CString GetObjectGroup() const + const std::string &GetObjectGroup() const { - return objectGroup_.value_or(""); + ASSERT(HasObjectGroup()); + return objectGroup_.value(); } bool HasObjectGroup() const @@ -644,17 +595,248 @@ private: NO_COPY_SEMANTIC(CallFunctionOnParams); NO_MOVE_SEMANTIC(CallFunctionOnParams); - CString functionDeclaration_ {}; + std::string functionDeclaration_ {}; std::optional objectId_ {}; - std::optional>> arguments_ {}; + std::optional>> arguments_ {}; std::optional silent_ {}; std::optional returnByValue_ {}; std::optional generatePreview_ {}; std::optional userGesture_ {}; std::optional awaitPromise_ {}; std::optional executionContextId_ {}; - std::optional objectGroup_ {}; + std::optional objectGroup_ {}; std::optional throwOnSideEffect_ {}; }; + +#ifdef SUPPORT_PROFILER_CDP +class StartSamplingParams : public PtBaseParams { +public: + StartSamplingParams() = default; + ~StartSamplingParams() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + int32_t GetSamplingInterval() const + { + return samplingInterval_.value_or(32768); + } + +private: + NO_COPY_SEMANTIC(StartSamplingParams); + NO_MOVE_SEMANTIC(StartSamplingParams); + + std::optional samplingInterval_ {32768}; +}; + +class StartTrackingHeapObjectsParams : public PtBaseParams { +public: + StartTrackingHeapObjectsParams() = default; + ~StartTrackingHeapObjectsParams() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + bool GetTrackAllocations() const + { + return trackAllocations_.value_or(false); + } + + bool HasTrackAllocations() const + { + return trackAllocations_.has_value(); + } + +private: + NO_COPY_SEMANTIC(StartTrackingHeapObjectsParams); + NO_MOVE_SEMANTIC(StartTrackingHeapObjectsParams); + + std::optional trackAllocations_; +}; + +class StopTrackingHeapObjectsParams : public PtBaseParams { +public: + StopTrackingHeapObjectsParams() = default; + ~StopTrackingHeapObjectsParams() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + bool GetReportProgress() const + { + return reportProgress_.value_or(false); + } + + bool HasReportProgress() const + { + return reportProgress_.has_value(); + } + + bool GetTreatGlobalObjectsAsRoots() const + { + return treatGlobalObjectsAsRoots_.value_or(false); + } + + bool HasTreatGlobalObjectsAsRoots() const + { + return treatGlobalObjectsAsRoots_.has_value(); + } + + bool GetCaptureNumericValue() const + { + return captureNumericValue_.value_or(false); + } + + bool HasCaptureNumericValue() const + { + return captureNumericValue_.has_value(); + } + +private: + NO_COPY_SEMANTIC(StopTrackingHeapObjectsParams); + NO_MOVE_SEMANTIC(StopTrackingHeapObjectsParams); + + std::optional reportProgress_ {}; + std::optional treatGlobalObjectsAsRoots_ {}; + std::optional captureNumericValue_ {}; +}; + +class AddInspectedHeapObjectParams : public PtBaseParams { +public: + AddInspectedHeapObjectParams() = default; + ~AddInspectedHeapObjectParams() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + HeapSnapshotObjectId GetHeapObjectId() const + { + return heapObjectId_; + } + +private: + NO_COPY_SEMANTIC(AddInspectedHeapObjectParams); + NO_MOVE_SEMANTIC(AddInspectedHeapObjectParams); + + HeapSnapshotObjectId heapObjectId_ {}; +}; + +class GetHeapObjectIdParams : public PtBaseParams { +public: + GetHeapObjectIdParams() = default; + ~GetHeapObjectIdParams() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + RemoteObjectId GetObjectId() const + { + return objectId_; + } + +private: + NO_COPY_SEMANTIC(GetHeapObjectIdParams); + NO_MOVE_SEMANTIC(GetHeapObjectIdParams); + + RemoteObjectId objectId_ {}; +}; + +class GetObjectByHeapObjectIdParams : public PtBaseParams { +public: + GetObjectByHeapObjectIdParams() = default; + ~GetObjectByHeapObjectIdParams() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + HeapSnapshotObjectId GetObjectId() const + { + return objectId_; + } + + const std::string &GetObjectGroup() const + { + ASSERT(HasObjectGroup()); + return objectGroup_.value(); + } + + bool HasObjectGroup() const + { + return objectGroup_.has_value(); + } + +private: + NO_COPY_SEMANTIC(GetObjectByHeapObjectIdParams); + NO_MOVE_SEMANTIC(GetObjectByHeapObjectIdParams); + + HeapSnapshotObjectId objectId_ {}; + std::optional objectGroup_ {}; +}; + +class StartPreciseCoverageParams : public PtBaseParams { +public: + StartPreciseCoverageParams() = default; + ~StartPreciseCoverageParams() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + bool GetCallCount() const + { + return callCount_.value_or(false); + } + + bool HasCallCount() const + { + return callCount_.has_value(); + } + + bool GetDetailed() const + { + return detailed_.value_or(false); + } + + bool HasDetailed() const + { + return detailed_.has_value(); + } + + bool GetAllowTriggeredUpdates() const + { + return allowTriggeredUpdates_.value_or(false); + } + + bool HasAllowTriggeredUpdates() const + { + return allowTriggeredUpdates_.has_value(); + } + +private: + NO_COPY_SEMANTIC(StartPreciseCoverageParams); + NO_MOVE_SEMANTIC(StartPreciseCoverageParams); + + std::optional callCount_ {}; + std::optional detailed_ {}; + std::optional allowTriggeredUpdates_ {}; +}; + +class SetSamplingIntervalParams : public PtBaseParams { +public: + SetSamplingIntervalParams() = default; + ~SetSamplingIntervalParams() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + int32_t GetInterval() const + { + return interval_; + } + + SetSamplingIntervalParams &SetInterval(int32_t interval) + { + interval_ = interval; + return *this; + } + +private: + NO_COPY_SEMANTIC(SetSamplingIntervalParams); + NO_MOVE_SEMANTIC(SetSamplingIntervalParams); + + int32_t interval_ {0}; +}; +#endif } // namespace panda::ecmascript::tooling #endif \ No newline at end of file diff --git a/ecmascript/tooling/base/pt_returns.cpp b/ecmascript/tooling/base/pt_returns.cpp index 17328d6f31e061d18484d30dd73073139417fbe8..a2232eade8f57ed6cc89da70f78fddcbf4239f8d 100644 --- a/ecmascript/tooling/base/pt_returns.cpp +++ b/ecmascript/tooling/base/pt_returns.cpp @@ -16,222 +16,295 @@ #include "ecmascript/tooling/base/pt_returns.h" namespace panda::ecmascript::tooling { -Local EnableReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr EnableReturns::ToJson() const { - Local result = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "debuggerId")), - Local(StringRef::NewFromUtf8(ecmaVm, debuggerId_.c_str()))); + result->Add("debuggerId", std::to_string(debuggerId_).c_str()); return result; } -Local SetBreakpointByUrlReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr SetBreakpointByUrlReturns::ToJson() const { + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("breakpointId", id_.c_str()); + std::unique_ptr array = PtJson::CreateArray(); size_t len = locations_.size(); - Local values = ArrayRef::New(ecmaVm, len); for (size_t i = 0; i < len; i++) { - Local location = locations_[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, location); + std::unique_ptr location = locations_[i]->ToJson(); + array->Push(location); } - - Local result = NewObject(ecmaVm); - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "breakpointId")), - Local(StringRef::NewFromUtf8(ecmaVm, id_.c_str()))); - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "locations")), values); + result->Add("locations", array); return result; } -Local EvaluateOnCallFrameReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr EvaluateOnCallFrameReturns::ToJson() const { - Local result = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - Local location = result_->ToObject(ecmaVm); - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "result")), Local(location)); + ASSERT(result_ != nullptr); + result->Add("result", result_->ToJson()); if (exceptionDetails_) { - Local exception = exceptionDetails_.value()->ToObject(ecmaVm); - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "exceptionDetails")), - Local(exception)); + ASSERT(exceptionDetails_.value() != nullptr); + result->Add("exceptionDetails", exceptionDetails_.value()->ToJson()); } return result; } -Local GetPossibleBreakpointsReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr GetPossibleBreakpointsReturns::ToJson() const { + std::unique_ptr result = PtJson::CreateObject(); + + std::unique_ptr array = PtJson::CreateArray(); size_t len = locations_.size(); - Local values = ArrayRef::New(ecmaVm, len); for (size_t i = 0; i < len; i++) { - Local location = locations_[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, location); + std::unique_ptr location = locations_[i]->ToJson(); + array->Push(location); } - - Local result = NewObject(ecmaVm); - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "locations")), values); + result->Add("locations", array); return result; } -Local GetScriptSourceReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr GetScriptSourceReturns::ToJson() const { - Local result = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptSource")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptSource_.c_str()))); + result->Add("scriptSource", scriptSource_.c_str()); if (bytecode_) { - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "bytecode")), - Local(StringRef::NewFromUtf8(ecmaVm, bytecode_->c_str()))); + result->Add("bytecode", bytecode_->c_str()); } return result; } -Local RestartFrameReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr RestartFrameReturns::ToJson() const { + std::unique_ptr result = PtJson::CreateObject(); + + std::unique_ptr array = PtJson::CreateArray(); size_t len = callFrames_.size(); - Local values = ArrayRef::New(ecmaVm, len); for (size_t i = 0; i < len; i++) { - Local location = callFrames_[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, location); + std::unique_ptr location = callFrames_[i]->ToJson(); + array->Push(location); } + result->Add("callFrames", array); - Local result = NewObject(ecmaVm); - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "callFrames")), values); return result; } -Local SearchInContentReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr SearchInContentReturns::ToJson() const { + std::unique_ptr result = PtJson::CreateObject(); + + std::unique_ptr array = PtJson::CreateArray(); size_t len = result_.size(); - Local values = ArrayRef::New(ecmaVm, len); for (size_t i = 0; i < len; i++) { - Local location = result_[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, location); + std::unique_ptr res = result_[i]->ToJson(); + array->Push(res); } - - Local result = NewObject(ecmaVm); - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "result")), values); + result->Add("result", array); return result; } -Local SetBreakpointReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr SetBreakpointReturns::ToJson() const { - Local result = NewObject(ecmaVm); - - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "breakpointId")), - Local(StringRef::NewFromUtf8(ecmaVm, breakpointId_.c_str()))); + std::unique_ptr result = PtJson::CreateObject(); - Local location = location_->ToObject(ecmaVm); - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "actualLocation")), - Local(location)); + result->Add("breakpointId", breakpointId_.c_str()); + result->Add("actualLocation", location_->ToJson()); return result; } -Local SetInstrumentationBreakpointReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr SetInstrumentationBreakpointReturns::ToJson() const { - Local result = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "breakpointId")), - Local(StringRef::NewFromUtf8(ecmaVm, breakpointId_.c_str()))); + result->Add("breakpointId", breakpointId_.c_str()); return result; } -Local SetScriptSourceReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr SetScriptSourceReturns::ToJson() const { - Local result = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); if (callFrames_) { - CVector> callFrame(std::move(callFrames_.value())); - size_t len = callFrame.size(); - Local values = ArrayRef::New(ecmaVm, len); + std::unique_ptr array = PtJson::CreateArray(); + size_t len = callFrames_->size(); for (size_t i = 0; i < len; i++) { - Local location = callFrame[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, location); + std::unique_ptr location = callFrames_.value()[i]->ToJson(); + array->Push(location); } - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "callFrames")), values); + result->Add("callFrames", array); } - if (stackChanged_) { - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "stackChanged")), - BooleanRef::New(ecmaVm, stackChanged_.value())); + result->Add("stackChanged", stackChanged_.value()); } - if (exceptionDetails_) { - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "exceptionDetails")), - Local(exceptionDetails_.value()->ToObject(ecmaVm))); + ASSERT(exceptionDetails_.value() != nullptr); + result->Add("exceptionDetails", exceptionDetails_.value()->ToJson()); } return result; } -Local GetPropertiesReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr GetPropertiesReturns::ToJson() const { - Local result = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); + std::unique_ptr array = PtJson::CreateArray(); size_t len = result_.size(); - Local values = ArrayRef::New(ecmaVm, len); for (size_t i = 0; i < len; i++) { - Local descriptor = result_[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, descriptor); + std::unique_ptr location = result_[i]->ToJson(); + array->Push(location); } - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "result")), values); + result->Add("result", array); if (internalPropertyDescripties_) { - auto descripties = std::move(internalPropertyDescripties_.value()); - len = descripties.size(); - values = ArrayRef::New(ecmaVm, len); + array = PtJson::CreateArray(); + len = internalPropertyDescripties_->size(); for (size_t i = 0; i < len; i++) { - Local descriptor = descripties[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, descriptor); + std::unique_ptr location = internalPropertyDescripties_.value()[i]->ToJson(); + array->Push(location); } - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "internalProperties")), values); + result->Add("internalProperties", array); } if (privateProperties_) { - auto descripties = std::move(privateProperties_.value()); - len = descripties.size(); - values = ArrayRef::New(ecmaVm, len); + array = PtJson::CreateArray(); + len = privateProperties_->size(); for (size_t i = 0; i < len; i++) { - Local descriptor = descripties[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, descriptor); + std::unique_ptr location = privateProperties_.value()[i]->ToJson(); + array->Push(location); } - result->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "privateProperties")), values); + result->Add("privateProperties", array); } if (exceptionDetails_) { - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "exceptionDetails")), - Local(exceptionDetails_.value()->ToObject(ecmaVm))); + ASSERT(exceptionDetails_.value() != nullptr); + result->Add("exceptionDetails", exceptionDetails_.value()->ToJson()); } return result; } -Local CallFunctionOnReturns::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr CallFunctionOnReturns::ToJson() const { - // For this - Local returns = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - // For this.result_ - Local result = result_->ToObject(ecmaVm); - returns->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "result")), - Local(result)); - // For this.exceptionDetails_ + result->Add("result", result_->ToJson()); if (exceptionDetails_) { - returns->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "exceptionDetails")), - Local(exceptionDetails_.value()->ToObject(ecmaVm))); + ASSERT(exceptionDetails_.value() != nullptr); + result->Add("exceptionDetails", exceptionDetails_.value()->ToJson()); + } + + return result; +} + +std::unique_ptr GetHeapUsageReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("usedSize", usedSize_); + result->Add("totalSize", totalSize_); + + return result; +} + +#ifdef SUPPORT_PROFILER_CDP +std::unique_ptr StopSamplingReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("profile", profile_->ToJson()); + + return result; +} + +std::unique_ptr GetHeapObjectIdReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("heapSnapshotObjectId", std::to_string(heapSnapshotObjectId_).c_str()); + + return result; +} + +std::unique_ptr GetObjectByHeapObjectIdReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("result", remoteObjectResult_->ToJson()); + + return result; +} + +std::unique_ptr StopReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("profile", profile_->ToJson()); + + return result; +} + +std::unique_ptr GetBestEffortCoverageReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + std::unique_ptr array = PtJson::CreateArray(); + size_t len = result_.size(); + for (size_t i = 0; i < len; i++) { + std::unique_ptr scriptCoverage = result_[i]->ToJson(); + array->Push(scriptCoverage); } + result->Add("result", array); + + return result; +} - return returns; +std::unique_ptr StartPreciseCoverageReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("timestamp", timestamp_); + + return result; +} + +std::unique_ptr TakePreciseCoverageReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + std::unique_ptr array = PtJson::CreateArray(); + size_t len = result_.size(); + for (size_t i = 0; i < len; i++) { + std::unique_ptr scriptTypeProfile = result_[i]->ToJson(); + array->Push(scriptTypeProfile); + } + result->Add("result", array); + result->Add("timestamp", timestamp_); + + return result; +} + +std::unique_ptr TakeTypeProfileReturns::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + std::unique_ptr array = PtJson::CreateArray(); + size_t len = result_.size(); + for (size_t i = 0; i < len; i++) { + std::unique_ptr scriptTypeProfile = result_[i]->ToJson(); + array->Push(scriptTypeProfile); + } + result->Add("result", array); + + return result; } -} // namespace panda::ecmascript::tooling +#endif +} // namespace panda::ecmascript::tooling \ No newline at end of file diff --git a/ecmascript/tooling/base/pt_returns.h b/ecmascript/tooling/base/pt_returns.h index 6615f8c7cf0e74a6b6f91877f4e90ce597f400a4..fd9268302d1bbdf2dfff351c84b0705619515c8a 100644 --- a/ecmascript/tooling/base/pt_returns.h +++ b/ecmascript/tooling/base/pt_returns.h @@ -19,16 +19,13 @@ #include "ecmascript/tooling/base/pt_types.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::CString; - class PtBaseReturns : public PtBaseTypes { public: PtBaseReturns() = default; ~PtBaseReturns() override = default; - - Local ToObject(const EcmaVM *ecmaVm) override + std::unique_ptr ToJson() const override { - return NewObject(ecmaVm); + return PtJson::CreateObject(); } private: @@ -38,10 +35,10 @@ private: class EnableReturns : public PtBaseReturns { public: - explicit EnableReturns(UniqueDebuggerId id) : debuggerId_(std::move(id)) {} + explicit EnableReturns(UniqueDebuggerId id) : debuggerId_(id) {} ~EnableReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: EnableReturns() = default; @@ -53,20 +50,20 @@ private: class SetBreakpointByUrlReturns : public PtBaseReturns { public: - explicit SetBreakpointByUrlReturns(CString id, CVector> locations) - : id_(std::move(id)), locations_(std::move(locations)) + explicit SetBreakpointByUrlReturns(const std::string &id, std::vector> locations) + : id_(id), locations_(std::move(locations)) {} ~SetBreakpointByUrlReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: SetBreakpointByUrlReturns() = default; NO_COPY_SEMANTIC(SetBreakpointByUrlReturns); NO_MOVE_SEMANTIC(SetBreakpointByUrlReturns); - CString id_ {}; - CVector> locations_ {}; + std::string id_ {}; + std::vector> locations_ {}; }; class EvaluateOnCallFrameReturns : public PtBaseReturns { @@ -76,7 +73,7 @@ public: : result_(std::move(result)), exceptionDetails_(std::move(exceptionDetails)) {} ~EvaluateOnCallFrameReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: EvaluateOnCallFrameReturns() = default; @@ -89,103 +86,104 @@ private: class GetPossibleBreakpointsReturns : public PtBaseReturns { public: - explicit GetPossibleBreakpointsReturns(CVector> locations) + explicit GetPossibleBreakpointsReturns(std::vector> locations) : locations_(std::move(locations)) {} ~GetPossibleBreakpointsReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: GetPossibleBreakpointsReturns() = default; NO_COPY_SEMANTIC(GetPossibleBreakpointsReturns); NO_MOVE_SEMANTIC(GetPossibleBreakpointsReturns); - CVector> locations_ {}; + std::vector> locations_ {}; }; class GetScriptSourceReturns : public PtBaseReturns { public: - explicit GetScriptSourceReturns(CString scriptSource, std::optional bytecode = std::nullopt) - : scriptSource_(std::move(scriptSource)), bytecode_(std::move(bytecode)) + explicit GetScriptSourceReturns(const std::string &scriptSource, std::optional bytecode = std::nullopt) + : scriptSource_(scriptSource), bytecode_(std::move(bytecode)) {} ~GetScriptSourceReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: GetScriptSourceReturns() = default; NO_COPY_SEMANTIC(GetScriptSourceReturns); NO_MOVE_SEMANTIC(GetScriptSourceReturns); - CString scriptSource_ {}; - std::optional bytecode_ {}; + std::string scriptSource_ {}; + std::optional bytecode_ {}; }; class RestartFrameReturns : public PtBaseReturns { public: - explicit RestartFrameReturns(CVector> callFrames) : callFrames_(std::move(callFrames)) + explicit RestartFrameReturns(std::vector> callFrames) + : callFrames_(std::move(callFrames)) {} ~RestartFrameReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: RestartFrameReturns() = default; NO_COPY_SEMANTIC(RestartFrameReturns); NO_MOVE_SEMANTIC(RestartFrameReturns); - CVector> callFrames_ {}; + std::vector> callFrames_ {}; }; class SearchInContentReturns : public PtBaseReturns { public: - explicit SearchInContentReturns(CVector> result) : result_(std::move(result)) + explicit SearchInContentReturns(std::vector> result) : result_(std::move(result)) {} ~SearchInContentReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: SearchInContentReturns() = default; NO_COPY_SEMANTIC(SearchInContentReturns); NO_MOVE_SEMANTIC(SearchInContentReturns); - CVector> result_ {}; + std::vector> result_ {}; }; class SetBreakpointReturns : public PtBaseReturns { public: - explicit SetBreakpointReturns(CString id, std::unique_ptr location) - : breakpointId_(std::move(id)), location_(std::move(location)) + explicit SetBreakpointReturns(const std::string &id, std::unique_ptr location) + : breakpointId_(id), location_(std::move(location)) {} ~SetBreakpointReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: SetBreakpointReturns() = default; NO_COPY_SEMANTIC(SetBreakpointReturns); NO_MOVE_SEMANTIC(SetBreakpointReturns); - CString breakpointId_ {}; + std::string breakpointId_ {}; std::unique_ptr location_ {}; }; class SetInstrumentationBreakpointReturns : public PtBaseReturns { public: - explicit SetInstrumentationBreakpointReturns(CString id) : breakpointId_(std::move(id)) + explicit SetInstrumentationBreakpointReturns(const std::string &id) : breakpointId_(id) {} ~SetInstrumentationBreakpointReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: SetInstrumentationBreakpointReturns() = default; NO_COPY_SEMANTIC(SetInstrumentationBreakpointReturns); NO_MOVE_SEMANTIC(SetInstrumentationBreakpointReturns); - CString breakpointId_ {}; + std::string breakpointId_ {}; }; class SetScriptSourceReturns : public PtBaseReturns { public: - explicit SetScriptSourceReturns(std::optional>> callFrames = std::nullopt, + explicit SetScriptSourceReturns(std::optional>> callFrames = std::nullopt, std::optional stackChanged = std::nullopt, std::optional> exceptionDetails = std::nullopt) : callFrames_(std::move(callFrames)), @@ -193,23 +191,23 @@ public: exceptionDetails_(std::move(exceptionDetails)) {} ~SetScriptSourceReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: SetScriptSourceReturns() = default; NO_COPY_SEMANTIC(SetScriptSourceReturns); NO_MOVE_SEMANTIC(SetScriptSourceReturns); - std::optional>> callFrames_ {}; + std::optional>> callFrames_ {}; std::optional stackChanged_ {}; std::optional> exceptionDetails_ {}; }; class GetPropertiesReturns : public PtBaseReturns { public: - explicit GetPropertiesReturns(CVector> descriptor, - std::optional>> internalDescripties = std::nullopt, - std::optional>> privateProperties = std::nullopt, + explicit GetPropertiesReturns(std::vector> descriptor, + std::optional>> internalDescripties = std::nullopt, + std::optional>> privateProperties = std::nullopt, std::optional> exceptionDetails = std::nullopt) : result_(std::move(descriptor)), internalPropertyDescripties_(std::move(internalDescripties)), @@ -217,16 +215,16 @@ public: exceptionDetails_(std::move(exceptionDetails)) {} ~GetPropertiesReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: GetPropertiesReturns() = default; NO_COPY_SEMANTIC(GetPropertiesReturns); NO_MOVE_SEMANTIC(GetPropertiesReturns); - CVector> result_ {}; - std::optional>> internalPropertyDescripties_ {}; - std::optional>> privateProperties_ {}; + std::vector> result_ {}; + std::optional>> internalPropertyDescripties_ {}; + std::optional>> privateProperties_ {}; std::optional> exceptionDetails_ {}; }; @@ -238,7 +236,7 @@ public: exceptionDetails_(std::move(exceptionDetails)) {} ~CallFunctionOnReturns() override = default; - Local ToObject(const EcmaVM *ecmaVm) override; + std::unique_ptr ToJson() const override; private: CallFunctionOnReturns() = default; @@ -248,5 +246,152 @@ private: std::unique_ptr result_ {}; std::optional> exceptionDetails_ {}; }; + +class GetHeapUsageReturns : public PtBaseReturns { +public: + explicit GetHeapUsageReturns(double usedSize, double totalSize) + : usedSize_(usedSize), totalSize_(totalSize) {} + ~GetHeapUsageReturns() override = default; + std::unique_ptr ToJson() const override; + +private: + GetHeapUsageReturns() = default; + NO_COPY_SEMANTIC(GetHeapUsageReturns); + NO_MOVE_SEMANTIC(GetHeapUsageReturns); + + double usedSize_ {0.0}; + double totalSize_ {0.0}; +}; + +#ifdef SUPPORT_PROFILER_CDP +class StopSamplingReturns : public PtBaseReturns { +public: + explicit StopSamplingReturns(std::unique_ptr profile) + : profile_(std::move(profile)) + {} + ~StopSamplingReturns() override = default; + + std::unique_ptr ToJson() const override; + +private: + StopSamplingReturns() = default; + NO_COPY_SEMANTIC(StopSamplingReturns); + NO_MOVE_SEMANTIC(StopSamplingReturns); + + std::unique_ptr profile_ {}; +}; + +class GetHeapObjectIdReturns : public PtBaseReturns { +public: + explicit GetHeapObjectIdReturns(HeapSnapshotObjectId heapSnapshotObjectId) + : heapSnapshotObjectId_(std::move(heapSnapshotObjectId)) + {} + ~GetHeapObjectIdReturns() override = default; + + std::unique_ptr ToJson() const override; + +private: + GetHeapObjectIdReturns() = default; + NO_COPY_SEMANTIC(GetHeapObjectIdReturns); + NO_MOVE_SEMANTIC(GetHeapObjectIdReturns); + + HeapSnapshotObjectId heapSnapshotObjectId_ {}; +}; + +class GetObjectByHeapObjectIdReturns : public PtBaseReturns { +public: + explicit GetObjectByHeapObjectIdReturns(std::unique_ptr remoteObjectResult) + : remoteObjectResult_(std::move(remoteObjectResult)) + {} + ~GetObjectByHeapObjectIdReturns() override = default; + + std::unique_ptr ToJson() const override; + +private: + GetObjectByHeapObjectIdReturns() = default; + NO_COPY_SEMANTIC(GetObjectByHeapObjectIdReturns); + NO_MOVE_SEMANTIC(GetObjectByHeapObjectIdReturns); + + std::unique_ptr remoteObjectResult_ {}; +}; + +class StopReturns : public PtBaseReturns { +public: + explicit StopReturns(std::unique_ptr profile) : profile_(std::move(profile)) {} + ~StopReturns() override = default; + std::unique_ptr ToJson() const override; + +private: + StopReturns() = default; + NO_COPY_SEMANTIC(StopReturns); + NO_MOVE_SEMANTIC(StopReturns); + + std::unique_ptr profile_ {}; +}; + +class GetBestEffortCoverageReturns : public PtBaseReturns { +public: + explicit GetBestEffortCoverageReturns(std::vector> result) + : result_(std::move(result)) + {} + ~GetBestEffortCoverageReturns() override = default; + std::unique_ptr ToJson() const override; + +private: + GetBestEffortCoverageReturns() = default; + NO_COPY_SEMANTIC(GetBestEffortCoverageReturns); + NO_MOVE_SEMANTIC(GetBestEffortCoverageReturns); + + std::vector> result_ {}; +}; + +class StartPreciseCoverageReturns : public PtBaseReturns { +public: + explicit StartPreciseCoverageReturns(int64_t tamp) : timestamp_(tamp) {} + ~StartPreciseCoverageReturns() override = default; + std::unique_ptr ToJson() const override; + +private: + StartPreciseCoverageReturns() = default; + NO_COPY_SEMANTIC(StartPreciseCoverageReturns); + NO_MOVE_SEMANTIC(StartPreciseCoverageReturns); + + int64_t timestamp_ {0}; +}; + +class TakePreciseCoverageReturns : public PtBaseReturns { +public: + explicit TakePreciseCoverageReturns(std::vector> result, int64_t tamp) + : result_(std::move(result)), + timestamp_(tamp) + {} + ~TakePreciseCoverageReturns() override = default; + std::unique_ptr ToJson() const override; + +private: + TakePreciseCoverageReturns() = default; + NO_COPY_SEMANTIC(TakePreciseCoverageReturns); + NO_MOVE_SEMANTIC(TakePreciseCoverageReturns); + + std::vector> result_ {}; + int64_t timestamp_ {0}; +}; + +class TakeTypeProfileReturns : public PtBaseReturns { +public: + explicit TakeTypeProfileReturns(std::vector> result) + : result_(std::move(result)) + {} + ~TakeTypeProfileReturns() override = default; + std::unique_ptr ToJson() const override; + +private: + TakeTypeProfileReturns() = default; + NO_COPY_SEMANTIC(TakeTypeProfileReturns); + NO_MOVE_SEMANTIC(TakeTypeProfileReturns); + + std::vector> result_ {}; +}; +#endif } // namespace panda::ecmascript::tooling #endif \ No newline at end of file diff --git a/ecmascript/tooling/base/pt_script.cpp b/ecmascript/tooling/base/pt_script.cpp index b0fcc2a0df3a6be1adf4607c4c9b0c75b5e3fddc..120442d93bae3eba26619a9ac51aab95efdf0818 100644 --- a/ecmascript/tooling/base/pt_script.cpp +++ b/ecmascript/tooling/base/pt_script.cpp @@ -14,14 +14,14 @@ */ #include "ecmascript/tooling/base/pt_script.h" -#include "ecmascript/tooling/interface/debugger_api.h" +#include "ecmascript/tooling/backend/debugger_api.h" namespace panda::ecmascript::tooling { -PtScript::PtScript(int32_t scriptId, CString fileName, CString url, CString source) - : scriptId_(DebuggerApi::ToCString(scriptId)), - fileName_(std::move(fileName)), - url_(std::move(url)), - scriptSource_(std::move(source)) +PtScript::PtScript(ScriptId scriptId, const std::string &fileName, const std::string &url, const std::string &source) + : scriptId_(scriptId), + fileName_(fileName), + url_(url), + scriptSource_(source) { endLine_ = std::count(scriptSource_.begin(), scriptSource_.end(), '\n'); } diff --git a/ecmascript/tooling/base/pt_script.h b/ecmascript/tooling/base/pt_script.h index 8169ef0c56d8d07782d047f940541a6a5d54463c..50f24dfa744ecbeb6c81bb7ddf89c43e799f0f14 100644 --- a/ecmascript/tooling/base/pt_script.h +++ b/ecmascript/tooling/base/pt_script.h @@ -17,13 +17,10 @@ #define ECMASCRIPT_TOOLING_BASE_PT_SCRIPT_H #include "libpandabase/macros.h" -#include "ecmascript/mem/c_string.h" +#include "ecmascript/tooling/base/pt_types.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::CString; - enum class ScriptMatchType : uint8_t { - SCRIPT_ID, URL, FILE_NAME, HASH, @@ -31,65 +28,65 @@ enum class ScriptMatchType : uint8_t { class PtScript { public: - PtScript(int32_t scriptId, CString fileName, CString url, CString source); + PtScript(ScriptId scriptId, const std::string &fileName, const std::string &url, const std::string &source); ~PtScript() = default; - CString GetScriptId() const + ScriptId GetScriptId() const { return scriptId_; } - void SetScriptId(const CString &scriptId) + void SetScriptId(ScriptId scriptId) { scriptId_ = scriptId; } - CString GetFileName() const + const std::string &GetFileName() const { return fileName_; } - void SetFileName(const CString &fileName) + void SetFileName(const std::string &fileName) { fileName_ = fileName; } - CString GetUrl() const + const std::string &GetUrl() const { return url_; } - void SetUrl(const CString &url) + void SetUrl(const std::string &url) { url_ = url; } - CString GetHash() const + const std::string &GetHash() const { return hash_; } - void SetHash(const CString &hash) + void SetHash(const std::string &hash) { hash_ = hash; } - CString GetScriptSource() const + const std::string &GetScriptSource() const { return scriptSource_; } - void SetScriptSource(const CString &scriptSource) + void SetScriptSource(const std::string &scriptSource) { scriptSource_ = scriptSource; } - CString GetSourceMapUrl() const + const std::string &GetSourceMapUrl() const { return sourceMapUrl_; } - void SetSourceMapUrl(const CString &sourceMapUrl) + void SetSourceMapUrl(const std::string &sourceMapUrl) { sourceMapUrl_ = sourceMapUrl; } @@ -108,12 +105,12 @@ private: NO_COPY_SEMANTIC(PtScript); NO_MOVE_SEMANTIC(PtScript); - CString scriptId_ {}; // start from 0, such as "0","1","2"... - CString fileName_ {}; // binary file name, such as xx.bin - CString url_ {}; // source file name, such as xx.js - CString hash_ {}; // js source file hash code - CString scriptSource_ {}; // js source code - CString sourceMapUrl_ {}; // source map url + ScriptId scriptId_ {0}; // start from 0, such as "0","1","2"... + std::string fileName_ {}; // binary file name, such as xx.bin + std::string url_ {}; // source file name, such as xx.js + std::string hash_ {}; // js source file hash code + std::string scriptSource_ {}; // js source code + std::string sourceMapUrl_ {}; // source map url int32_t endLine_ {0}; // total line number of source file }; } // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/base/pt_types.cpp b/ecmascript/tooling/base/pt_types.cpp index 990a94938d5afa9d833a2820692bce0d2638dcf5..0d6371df012857944c19f4f51827d0c7b72a7d06 100644 --- a/ecmascript/tooling/base/pt_types.cpp +++ b/ecmascript/tooling/base/pt_types.cpp @@ -15,87 +15,84 @@ #include "pt_types.h" +#ifdef SUPPORT_PROFILER_CDP +#include "ecmascript/dfx/cpu_profiler/samples_record.h" +#endif + namespace panda::ecmascript::tooling { using ObjectType = RemoteObject::TypeName; using ObjectSubType = RemoteObject::SubTypeName; using ObjectClassName = RemoteObject::ClassName; -const CString ObjectType::Object = "object"; // NOLINT (readability-identifier-naming) -const CString ObjectType::Function = "function"; // NOLINT (readability-identifier-naming) -const CString ObjectType::Undefined = "undefined"; // NOLINT (readability-identifier-naming) -const CString ObjectType::String = "string"; // NOLINT (readability-identifier-naming) -const CString ObjectType::Number = "number"; // NOLINT (readability-identifier-naming) -const CString ObjectType::Boolean = "boolean"; // NOLINT (readability-identifier-naming) -const CString ObjectType::Symbol = "symbol"; // NOLINT (readability-identifier-naming) -const CString ObjectType::Bigint = "bigint"; // NOLINT (readability-identifier-naming) -const CString ObjectType::Wasm = "wasm"; // NOLINT (readability-identifier-naming) - -const CString ObjectSubType::Array = "array"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Null = "null"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Node = "node"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Regexp = "regexp"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Date = "date"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Map = "map"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Set = "set"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Weakmap = "weakmap"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Weakset = "weakset"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Iterator = "iterator"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Generator = "generator"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Error = "error"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Proxy = "proxy"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Promise = "promise"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Typedarray = "typedarray"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Arraybuffer = "arraybuffer"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Dataview = "dataview"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::I32 = "i32"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::I64 = "i64"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::F32 = "f32"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::F64 = "f64"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::V128 = "v128"; // NOLINT (readability-identifier-naming) -const CString ObjectSubType::Externref = "externref"; // NOLINT (readability-identifier-naming) - -const CString ObjectClassName::Object = "Object"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Function = "Function"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Array = "Array"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Regexp = "RegExp"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Date = "Date"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Map = "Map"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Set = "Set"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Weakmap = "Weakmap"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Weakset = "Weakset"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::ArrayIterator = "ArrayIterator"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::StringIterator = "StringIterator"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::SetIterator = "SetIterator"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::MapIterator = "MapIterator"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Iterator = "Iterator"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Error = "Error"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Proxy = "Object"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Promise = "Promise"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Typedarray = "Typedarray"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Arraybuffer = "Arraybuffer"; // NOLINT (readability-identifier-naming) -const CString ObjectClassName::Global = "global"; // NOLINT (readability-identifier-naming) - -const CString RemoteObject::ObjectDescription = "Object"; // NOLINT (readability-identifier-naming) -const CString RemoteObject::GlobalDescription = "global"; // NOLINT (readability-identifier-naming) -const CString RemoteObject::ProxyDescription = "Proxy"; // NOLINT (readability-identifier-naming) -const CString RemoteObject::PromiseDescription = "Promise"; // NOLINT (readability-identifier-naming) -const CString RemoteObject::ArrayIteratorDescription = // NOLINT (readability-identifier-naming) +const std::string ObjectType::Object = "object"; // NOLINT (readability-identifier-naming) +const std::string ObjectType::Function = "function"; // NOLINT (readability-identifier-naming) +const std::string ObjectType::Undefined = "undefined"; // NOLINT (readability-identifier-naming) +const std::string ObjectType::String = "string"; // NOLINT (readability-identifier-naming) +const std::string ObjectType::Number = "number"; // NOLINT (readability-identifier-naming) +const std::string ObjectType::Boolean = "boolean"; // NOLINT (readability-identifier-naming) +const std::string ObjectType::Symbol = "symbol"; // NOLINT (readability-identifier-naming) +const std::string ObjectType::Bigint = "bigint"; // NOLINT (readability-identifier-naming) +const std::string ObjectType::Wasm = "wasm"; // NOLINT (readability-identifier-naming) + +const std::string ObjectSubType::Array = "array"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Null = "null"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Node = "node"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Regexp = "regexp"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Date = "date"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Map = "map"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Set = "set"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Weakmap = "weakmap"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Weakset = "weakset"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Iterator = "iterator"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Generator = "generator"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Error = "error"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Proxy = "proxy"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Promise = "promise"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Typedarray = "typedarray"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Arraybuffer = "arraybuffer"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Dataview = "dataview"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::I32 = "i32"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::I64 = "i64"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::F32 = "f32"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::F64 = "f64"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::V128 = "v128"; // NOLINT (readability-identifier-naming) +const std::string ObjectSubType::Externref = "externref"; // NOLINT (readability-identifier-naming) + +const std::string ObjectClassName::Object = "Object"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Function = "Function"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Array = "Array"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Regexp = "RegExp"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Date = "Date"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Map = "Map"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Set = "Set"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Weakmap = "Weakmap"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Weakset = "Weakset"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::ArrayIterator = "ArrayIterator"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::StringIterator = "StringIterator"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::SetIterator = "SetIterator"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::MapIterator = "MapIterator"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Iterator = "Iterator"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Error = "Error"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Proxy = "Object"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Promise = "Promise"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Typedarray = "Typedarray"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Arraybuffer = "Arraybuffer"; // NOLINT (readability-identifier-naming) +const std::string ObjectClassName::Global = "global"; // NOLINT (readability-identifier-naming) + +const std::string RemoteObject::ObjectDescription = "Object"; // NOLINT (readability-identifier-naming) +const std::string RemoteObject::GlobalDescription = "global"; // NOLINT (readability-identifier-naming) +const std::string RemoteObject::ProxyDescription = "Proxy"; // NOLINT (readability-identifier-naming) +const std::string RemoteObject::PromiseDescription = "Promise"; // NOLINT (readability-identifier-naming) +const std::string RemoteObject::ArrayIteratorDescription = // NOLINT (readability-identifier-naming) "ArrayIterator"; -const CString RemoteObject::StringIteratorDescription = // NOLINT (readability-identifier-naming) +const std::string RemoteObject::StringIteratorDescription = // NOLINT (readability-identifier-naming) "StringIterator"; -const CString RemoteObject::SetIteratorDescription = "SetIterator"; // NOLINT (readability-identifier-naming) -const CString RemoteObject::MapIteratorDescription = "MapIterator"; // NOLINT (readability-identifier-naming) -const CString RemoteObject::WeakMapDescription = "WeakMap"; // NOLINT (readability-identifier-naming) -const CString RemoteObject::WeakSetDescription = "WeakSet"; // NOLINT (readability-identifier-naming) - -static constexpr uint64_t DOUBLE_SIGN_MASK = 0x8000000000000000ULL; - -Local PtBaseTypes::NewObject(const EcmaVM *ecmaVm) -{ - return ObjectRef::New(ecmaVm); -} +const std::string RemoteObject::SetIteratorDescription = "SetIterator"; // NOLINT (readability-identifier-naming) +const std::string RemoteObject::MapIteratorDescription = "MapIterator"; // NOLINT (readability-identifier-naming) +const std::string RemoteObject::WeakMapDescription = "WeakMap"; // NOLINT (readability-identifier-naming) +const std::string RemoteObject::WeakSetDescription = "WeakSet"; // NOLINT (readability-identifier-naming) -std::unique_ptr RemoteObject::FromTagged(const EcmaVM *ecmaVm, const Local &tagged) +std::unique_ptr RemoteObject::FromTagged(const EcmaVM *ecmaVm, Local tagged) { if (tagged->IsNull() || tagged->IsUndefined() || tagged->IsBoolean() || tagged->IsNumber() || @@ -103,10 +100,10 @@ std::unique_ptr RemoteObject::FromTagged(const EcmaVM *ecmaVm, con return std::make_unique(ecmaVm, tagged); } if (tagged->IsString()) { - return std::make_unique(ecmaVm, tagged); + return std::make_unique(ecmaVm, Local(tagged)); } if (tagged->IsSymbol()) { - return std::make_unique(ecmaVm, tagged); + return std::make_unique(ecmaVm, Local(tagged)); } if (tagged->IsFunction()) { return std::make_unique(ecmaVm, tagged); @@ -167,30 +164,85 @@ std::unique_ptr RemoteObject::FromTagged(const EcmaVM *ecmaVm, con return object; } -PrimitiveRemoteObject::PrimitiveRemoteObject(const EcmaVM *ecmaVm, const Local &tagged) +PrimitiveRemoteObject::PrimitiveRemoteObject(const EcmaVM *ecmaVm, Local tagged) { if (tagged->IsNull()) { - this->SetType(ObjectType::Object).SetSubType(ObjectSubType::Null).SetValue(tagged); + SetType(ObjectType::Object).SetSubType(ObjectSubType::Null); } else if (tagged->IsBoolean()) { - this->SetType(ObjectType::Boolean).SetValue(tagged); + std::string description = tagged->IsTrue() ? "true" : "false"; + SetType(ObjectType::Boolean) + .SetValue(tagged) + .SetUnserializableValue(description) + .SetDescription(description); } else if (tagged->IsUndefined()) { - this->SetType(ObjectType::Undefined); + SetType(ObjectType::Undefined); } else if (tagged->IsNumber()) { - this->SetType(ObjectType::Number) - .SetDescription(DebuggerApi::ConvertToString(tagged->ToString(ecmaVm)->ToString())); - double val = Local(tagged)->Value(); - if (!std::isfinite(val) || (val == 0 && ((bit_cast(val) & DOUBLE_SIGN_MASK) == DOUBLE_SIGN_MASK))) { - this->SetUnserializableValue(this->GetDescription()); - } else { - this->SetValue(tagged); - } + std::string description = tagged->ToString(ecmaVm)->ToString(); + SetType(ObjectType::Number) + .SetValue(tagged) + .SetUnserializableValue(description) + .SetDescription(description); } else if (tagged->IsBigInt()) { - std::string literal = tagged->ToString(ecmaVm)->ToString() + "n"; // n : BigInt literal postfix - this->SetType(ObjectType::Bigint).SetValue(StringRef::NewFromUtf8(ecmaVm, literal.data())); + std::string description = tagged->ToString(ecmaVm)->ToString() + "n"; // n : BigInt literal postfix + SetType(ObjectType::Bigint) + .SetValue(tagged) + .SetUnserializableValue(description) + .SetDescription(description); } } -CString ObjectRemoteObject::DescriptionForObject(const EcmaVM *ecmaVm, const Local &tagged) +StringRemoteObject::StringRemoteObject([[maybe_unused]] const EcmaVM *ecmaVm, Local tagged) +{ + std::string description = tagged->ToString(); + SetType(RemoteObject::TypeName::String) + .SetValue(tagged) + .SetUnserializableValue(description) + .SetDescription(description); +} + +SymbolRemoteObject::SymbolRemoteObject(const EcmaVM *ecmaVm, Local tagged) +{ + std::string description = DescriptionForSymbol(ecmaVm, tagged); + SetType(RemoteObject::TypeName::Symbol) + .SetValue(tagged) + .SetUnserializableValue(description) + .SetDescription(description); +} + +FunctionRemoteObject::FunctionRemoteObject(const EcmaVM *ecmaVm, Local tagged) +{ + std::string description = DescriptionForFunction(ecmaVm, tagged); + SetType(RemoteObject::TypeName::Function) + .SetClassName(RemoteObject::ClassName::Function) + .SetValue(tagged) + .SetUnserializableValue(description) + .SetDescription(description); +} + +ObjectRemoteObject::ObjectRemoteObject(const EcmaVM *ecmaVm, Local tagged, + const std::string &classname) +{ + std::string description = DescriptionForObject(ecmaVm, tagged); + SetType(RemoteObject::TypeName::Object) + .SetClassName(classname) + .SetValue(tagged) + .SetUnserializableValue(description) + .SetDescription(description); +} + +ObjectRemoteObject::ObjectRemoteObject(const EcmaVM *ecmaVm, Local tagged, + const std::string &classname, const std::string &subtype) +{ + std::string description = DescriptionForObject(ecmaVm, tagged); + SetType(RemoteObject::TypeName::Object) + .SetSubType(subtype) + .SetClassName(classname) + .SetValue(tagged) + .SetUnserializableValue(description) + .SetDescription(description); +} + +std::string ObjectRemoteObject::DescriptionForObject(const EcmaVM *ecmaVm, Local tagged) { if (tagged->IsArray(ecmaVm)) { return DescriptionForArray(ecmaVm, Local(tagged)); @@ -240,147 +292,133 @@ CString ObjectRemoteObject::DescriptionForObject(const EcmaVM *ecmaVm, const Loc return RemoteObject::ObjectDescription; } -CString ObjectRemoteObject::DescriptionForArray(const EcmaVM *ecmaVm, const Local &tagged) +std::string ObjectRemoteObject::DescriptionForArray(const EcmaVM *ecmaVm, Local tagged) { - CString description = "Array(" + DebuggerApi::ToCString(tagged->Length(ecmaVm)) + ")"; + std::string description = "Array(" + std::to_string(tagged->Length(ecmaVm)) + ")"; return description; } -CString ObjectRemoteObject::DescriptionForRegexp(const EcmaVM *ecmaVm, const Local &tagged) +std::string ObjectRemoteObject::DescriptionForRegexp(const EcmaVM *ecmaVm, Local tagged) { - CString regexpSource = DebuggerApi::ConvertToString(tagged->GetOriginalSource(ecmaVm)->ToString()); - CString description = "/" + regexpSource + "/"; + std::string regexpSource = tagged->GetOriginalSource(ecmaVm)->ToString(); + std::string description = "/" + regexpSource + "/"; return description; } -CString ObjectRemoteObject::DescriptionForDate(const EcmaVM *ecmaVm, const Local &tagged) +std::string ObjectRemoteObject::DescriptionForDate(const EcmaVM *ecmaVm, Local tagged) { - CString description = DebuggerApi::ConvertToString(tagged->ToString(ecmaVm)->ToString()); + std::string description = tagged->ToString(ecmaVm)->ToString(); return description; } -CString ObjectRemoteObject::DescriptionForMap(const Local &tagged) +std::string ObjectRemoteObject::DescriptionForMap(Local tagged) { - CString description = ("Map(" + DebuggerApi::ToCString(tagged->GetSize()) + ")"); + std::string description = ("Map(" + std::to_string(tagged->GetSize()) + ")"); return description; } -CString ObjectRemoteObject::DescriptionForSet(const Local &tagged) +std::string ObjectRemoteObject::DescriptionForSet(Local tagged) { - CString description = ("Set(" + DebuggerApi::ToCString(tagged->GetSize()) + ")"); + std::string description = ("Set(" + std::to_string(tagged->GetSize()) + ")"); return description; } -CString ObjectRemoteObject::DescriptionForError(const EcmaVM *ecmaVm, const Local &tagged) +std::string ObjectRemoteObject::DescriptionForError(const EcmaVM *ecmaVm, Local tagged) { // add message Local stack = StringRef::NewFromUtf8(ecmaVm, "message"); Local result = Local(tagged)->Get(ecmaVm, stack); - return DebuggerApi::ConvertToString(result->ToString(ecmaVm)->ToString()); + return result->ToString(ecmaVm)->ToString(); } -CString ObjectRemoteObject::DescriptionForArrayBuffer(const EcmaVM *ecmaVm, const Local &tagged) +std::string ObjectRemoteObject::DescriptionForArrayBuffer(const EcmaVM *ecmaVm, Local tagged) { int32_t len = tagged->ByteLength(ecmaVm); - CString description = ("ArrayBuffer(" + DebuggerApi::ToCString(len) + ")"); + std::string description = ("ArrayBuffer(" + std::to_string(len) + ")"); return description; } -CString SymbolRemoteObject::DescriptionForSymbol(const EcmaVM *ecmaVm, const Local &tagged) const +std::string SymbolRemoteObject::DescriptionForSymbol(const EcmaVM *ecmaVm, Local tagged) const { - CString description = - "Symbol(" + DebuggerApi::ConvertToString(Local(tagged->GetDescription(ecmaVm))->ToString()) + ")"; + std::string description = "Symbol(" + tagged->GetDescription(ecmaVm)->ToString() + ")"; return description; } -CString FunctionRemoteObject::DescriptionForFunction(const EcmaVM *ecmaVm, const Local &tagged) const +std::string FunctionRemoteObject::DescriptionForFunction(const EcmaVM *ecmaVm, Local tagged) const { - CString sourceCode; + std::string sourceCode; if (tagged->IsNative(ecmaVm)) { sourceCode = "[native code]"; } else { sourceCode = "[js code]"; } Local name = tagged->GetName(ecmaVm); - CString description = "function " + DebuggerApi::ConvertToString(name->ToString()) + "() { " + sourceCode + " }"; + std::string description = "function " + name->ToString() + "( { " + sourceCode + " }"; return description; } -std::unique_ptr RemoteObject::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr RemoteObject::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "RemoteObject::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto remoteObject = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "type"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - auto type = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - if (ObjectType::Valid(type)) { - remoteObject->type_ = type; - } else { - error += "'type' is invalid;"; - } + std::string type; + ret = params.GetString("type", &type); + if (ret == Result::SUCCESS) { + if (ObjectType::Valid(type)) { + remoteObject->type_ = std::move(type); } else { - error += "'type' should be a String;"; + error += "'type' is invalid;"; } } else { - error += "should contain 'type';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "subtype"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - auto type = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - if (ObjectSubType::Valid(type)) { - remoteObject->subtype_ = type; - } else { - error += "'subtype' is invalid;"; - } - } else { - error += "'subtype' should be a String;"; - } + error += "Unknown 'type';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "className"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - remoteObject->className_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); + + std::string subType; + ret = params.GetString("subtype", &subType); + if (ret == Result::SUCCESS) { + if (ObjectSubType::Valid(subType)) { + remoteObject->subType_ = std::move(subType); } else { - error += "'className' should be a String;"; + error += "'subtype' is invalid;"; } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'subtype';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "value"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - remoteObject->value_ = result; + + std::string className; + ret = params.GetString("className", &className); + if (ret == Result::SUCCESS) { + remoteObject->className_ = std::move(className); + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'className';"; } - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "unserializableValue"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - remoteObject->unserializableValue_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'unserializableValue' should be a String;"; - } + + std::string unserializableValue; + ret = params.GetString("unserializableValue", &unserializableValue); + if (ret == Result::SUCCESS) { + remoteObject->unserializableValue_ = std::move(unserializableValue); + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'unserializableValue';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "description"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - remoteObject->description_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'description' should be a String;"; - } + + std::string description; + ret = params.GetString("description", &description); + if (ret == Result::SUCCESS) { + remoteObject->description_ = std::move(description); + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'description';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "objectId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - remoteObject->objectId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'objectId' should be a String;"; - } + + std::string objectId; + ret = params.GetString("objectId", &objectId); + if (ret == Result::SUCCESS) { + remoteObject->objectId_ = std::stoi(objectId); + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'objectId';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "RemoteObject::Create " << error; return nullptr; @@ -389,134 +427,105 @@ std::unique_ptr RemoteObject::Create(const EcmaVM *ecmaVm, const L return remoteObject; } -Local RemoteObject::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr RemoteObject::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "type")), - Local(StringRef::NewFromUtf8(ecmaVm, type_.c_str()))); - if (subtype_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "subtype")), - Local(StringRef::NewFromUtf8(ecmaVm, subtype_->c_str()))); + result->Add("type", type_.c_str()); + if (subType_) { + result->Add("subtype", subType_->c_str()); } if (className_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "className")), - Local(StringRef::NewFromUtf8(ecmaVm, className_->c_str()))); - } - if (value_) { - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "value")), value_.value()); + result->Add("className", className_->c_str()); } if (unserializableValue_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "unserializableValue")), - Local(StringRef::NewFromUtf8(ecmaVm, unserializableValue_->c_str()))); + result->Add("unserializableValue", unserializableValue_->c_str()); } if (description_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "description")), - Local(StringRef::NewFromUtf8(ecmaVm, description_->c_str()))); + result->Add("description", description_->c_str()); } if (objectId_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "objectId")), - Local(StringRef::NewFromUtf8(ecmaVm, objectId_->c_str()))); + result->Add("objectId", std::to_string(objectId_.value()).c_str()); } - return params; + return result; } -std::unique_ptr ExceptionDetails::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr ExceptionDetails::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "ExceptionDetails::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto exceptionDetails = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "exceptionId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - exceptionDetails->exceptionId_ = static_cast(Local(result)->Value()); - } else { - error += "'exceptionId' should be a Number;"; - } + int32_t exceptionId; + ret = params.GetInt("exceptionId", &exceptionId); + if (ret == Result::SUCCESS) { + exceptionDetails->exceptionId_ = exceptionId; } else { - error += "should contain 'exceptionId';"; + error += "Unknown 'exceptionId';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "text"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - exceptionDetails->text_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'text' should be a String;"; - } + + std::string text; + ret = params.GetString("text", &text); + if (ret == Result::SUCCESS) { + exceptionDetails->text_ = std::move(text); } else { - error += "should contain 'text';"; + error += "Unknown 'text';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - exceptionDetails->line_ = static_cast(Local(result)->Value()); - } else { - error += "'lineNumber' should be a Number;"; - } + + int32_t lineNumber; + ret = params.GetInt("lineNumber", &lineNumber); + if (ret == Result::SUCCESS) { + exceptionDetails->lineNumber_ = lineNumber; } else { - error += "should contain 'lineNumber';"; + error += "Unknown 'lineNumber';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - exceptionDetails->column_ = static_cast(Local(result)->Value()); - } else { - error += "'columnNumber' should be a Number;"; - } + + int32_t columnNumber; + ret = params.GetInt("columnNumber", &columnNumber); + if (ret == Result::SUCCESS) { + exceptionDetails->columnNumber_ = columnNumber; } else { - error += "should contain 'columnNumber';"; + error += "Unknown 'columnNumber';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - exceptionDetails->scriptId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptId' should be a String;"; - } + + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + exceptionDetails->scriptId_ = std::stoi(scriptId); + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'scriptId';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "url"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - exceptionDetails->url_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'url' should be a String;"; - } + + std::string url; + ret = params.GetString("url", &url); + if (ret == Result::SUCCESS) { + exceptionDetails->url_ = std::move(url); + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'url';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "exception"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'exception' format error;"; - } else { - exceptionDetails->exception_ = std::move(obj); - } + + std::unique_ptr exception; + ret = params.GetObject("exception", &exception); + if (ret == Result::SUCCESS) { + std::unique_ptr obj = RemoteObject::Create(*exception); + if (obj == nullptr) { + error += "'exception' format error;"; } else { - error += "'exception' should be an Object;"; + exceptionDetails->exception_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'exception';"; } - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "executionContextId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - exceptionDetails->executionContextId_ = static_cast(Local(result)->Value()); - } else { - error += "'executionContextId' should be a Number;"; - } + int32_t executionContextId; + ret = params.GetInt("executionContextId", &executionContextId); + if (ret == Result::SUCCESS) { + exceptionDetails->executionContextId_ = executionContextId; + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'executionContextId';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "ExceptionDetails::Create " << error; return nullptr; @@ -525,79 +534,59 @@ std::unique_ptr ExceptionDetails::Create(const EcmaVM *ecmaVm, return exceptionDetails; } -Local ExceptionDetails::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr ExceptionDetails::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("exceptionId", exceptionId_); + result->Add("text", text_.c_str()); + result->Add("lineNumber", lineNumber_); + result->Add("columnNumber", columnNumber_); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "exceptionId")), - IntegerRef::New(ecmaVm, exceptionId_)); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "text")), - Local(StringRef::NewFromUtf8(ecmaVm, text_.c_str()))); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber")), - IntegerRef::New(ecmaVm, line_)); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber")), - IntegerRef::New(ecmaVm, column_)); if (scriptId_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptId")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptId_->c_str()))); + result->Add("scriptId", std::to_string(scriptId_.value()).c_str()); } if (url_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "url")), - Local(StringRef::NewFromUtf8(ecmaVm, url_->c_str()))); + result->Add("url", url_->c_str()); } if (exception_) { ASSERT(exception_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "exception")), - Local(exception_.value()->ToObject(ecmaVm))); + result->Add("exception", exception_.value()->ToJson()); } if (executionContextId_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "executionContextId")), - IntegerRef::New(ecmaVm, executionContextId_.value())); + result->Add("executionContextId", executionContextId_.value()); } - return params; + return result; } -std::unique_ptr InternalPropertyDescriptor::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr InternalPropertyDescriptor::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "InternalPropertyDescriptor::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto internalPropertyDescriptor = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "name"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - internalPropertyDescriptor->name_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'name' should be a String;"; - } + std::string name; + ret = params.GetString("name", &name); + if (ret == Result::SUCCESS) { + internalPropertyDescriptor->name_ = std::move(name); } else { - error += "should contain 'name';"; + error += "Unknown 'name';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "value"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'value' format error;"; - } else { - internalPropertyDescriptor->value_ = std::move(obj); - } + + std::unique_ptr value; + ret = params.GetObject("value", &value); + if (ret == Result::SUCCESS) { + std::unique_ptr obj = RemoteObject::Create(*value); + if (obj == nullptr) { + error += "'value' format error;"; } else { - error += "'value' should be an Object;"; + internalPropertyDescriptor->value_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'value';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "InternalPropertyDescriptor::Create " << error; return nullptr; @@ -606,133 +595,114 @@ std::unique_ptr InternalPropertyDescriptor::Create(c return internalPropertyDescriptor; } -Local InternalPropertyDescriptor::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr InternalPropertyDescriptor::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "name")), - Local(StringRef::NewFromUtf8(ecmaVm, name_.c_str()))); + result->Add("name", name_.c_str()); if (value_) { ASSERT(value_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "value")), - Local(value_.value()->ToObject(ecmaVm))); + result->Add("value", value_.value()->ToJson()); } - return params; + return result; } -std::unique_ptr PrivatePropertyDescriptor::Create(const EcmaVM *ecmaVm, - const Local ¶ms) +std::unique_ptr PrivatePropertyDescriptor::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "PrivatePropertyDescriptor::Create params is nullptr"; - return nullptr; - } - CString error; - auto propertyDescriptor = std::make_unique(); - - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "name"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - propertyDescriptor->name_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'name' should be a String;"; - } + std::string error; + auto privatePropertyDescriptor = std::make_unique(); + Result ret; + + std::string name; + ret = params.GetString("name", &name); + if (ret == Result::SUCCESS) { + privatePropertyDescriptor->name_ = std::move(name); } else { - error += "should contain 'name';"; + error += "Unknown 'name';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "value"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'value' format error;"; - } else { - propertyDescriptor->value_ = std::move(obj); - } + + std::unique_ptr value; + ret = params.GetObject("value", &value); + std::unique_ptr obj; + if (ret == Result::SUCCESS) { + obj = RemoteObject::Create(*value); + if (obj == nullptr) { + error += "'value' format error;"; } else { - error += "'value' should be a Object;"; + privatePropertyDescriptor->value_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'value';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "get"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'get' format error;"; - } else { - propertyDescriptor->get_ = std::move(obj); - } + + std::unique_ptr get; + ret = params.GetObject("get", &get); + if (ret == Result::SUCCESS) { + obj = RemoteObject::Create(*get); + if (obj == nullptr) { + error += "'get' format error;"; } else { - error += "'get' should be an Object;"; + privatePropertyDescriptor->get_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'get';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "set"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'set' format error;"; - } else { - propertyDescriptor->set_ = std::move(obj); - } + + std::unique_ptr set; + ret = params.GetObject("set", &set); + if (ret == Result::SUCCESS) { + obj = RemoteObject::Create(*set); + if (obj == nullptr) { + error += "'set' format error;"; } else { - error += "'set' should be an Object;"; + privatePropertyDescriptor->set_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'set';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "PrivatePropertyDescriptor::Create " << error; return nullptr; } - return propertyDescriptor; + return privatePropertyDescriptor; } -Local PrivatePropertyDescriptor::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr PrivatePropertyDescriptor::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "name")), - Local(StringRef::NewFromUtf8(ecmaVm, name_.c_str()))); + result->Add("name", name_.c_str()); if (value_) { ASSERT(value_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "value")), - Local(value_.value()->ToObject(ecmaVm))); + result->Add("value", value_.value()->ToJson()); } if (get_) { ASSERT(get_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "get")), - Local(get_.value()->ToObject(ecmaVm))); + result->Add("get", get_.value()->ToJson()); } if (set_) { ASSERT(set_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "set")), - Local(set_.value()->ToObject(ecmaVm))); + result->Add("set", set_.value()->ToJson()); } - return params; + return result; } std::unique_ptr PropertyDescriptor::FromProperty(const EcmaVM *ecmaVm, - const Local &name, const PropertyAttribute &property) + Local name, const PropertyAttribute &property) { std::unique_ptr debuggerProperty = std::make_unique(); - CString nameStr; + std::string nameStr; if (name->IsSymbol()) { Local symbol(name); - nameStr = - "Symbol(" + DebuggerApi::ConvertToString(Local(name)->GetDescription(ecmaVm)->ToString()) + ")"; + nameStr = "Symbol(" + Local(name)->GetDescription(ecmaVm)->ToString() + ")"; debuggerProperty->symbol_ = RemoteObject::FromTagged(ecmaVm, name); } else { - nameStr = DebuggerApi::ConvertToString(name->ToString(ecmaVm)->ToString()); + nameStr = name->ToString(ecmaVm)->ToString(); } debuggerProperty->name_ = nameStr; @@ -755,122 +725,113 @@ std::unique_ptr PropertyDescriptor::FromProperty(const EcmaV return debuggerProperty; } -std::unique_ptr PropertyDescriptor::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr PropertyDescriptor::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "PropertyDescriptor::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto propertyDescriptor = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "name"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - propertyDescriptor->name_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'name' should be a String;"; - } + std::string name; + ret = params.GetString("name", &name); + if (ret == Result::SUCCESS) { + propertyDescriptor->name_ = std::move(name); } else { - error += "should contain 'name';"; + error += "Unknown 'name';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "value"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'value' format error;"; - } else { - propertyDescriptor->value_ = std::move(obj); - } + + std::unique_ptr value; + std::unique_ptr obj; + ret = params.GetObject("value", &value); + if (ret == Result::SUCCESS) { + obj = RemoteObject::Create(*value); + if (obj == nullptr) { + error += "'value' format error;"; } else { - error += "'value' should be an Object;"; + propertyDescriptor->value_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'value';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "writable"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - propertyDescriptor->writable_ = result->IsTrue(); - } else { - error += "'writable' should be a Boolean;"; - } + + bool writable; + ret = params.GetBool("writable", &writable); + if (ret == Result::SUCCESS) { + propertyDescriptor->writable_ = writable; + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'writable';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "get"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'get' format error;"; - } else { - propertyDescriptor->get_ = std::move(obj); - } + + std::unique_ptr get; + ret = params.GetObject("get", &get); + if (ret == Result::SUCCESS) { + obj = RemoteObject::Create(*get); + if (obj == nullptr) { + error += "'get' format error;"; } else { - error += "'get' should be an Object;"; + propertyDescriptor->get_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'get';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "set"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'set' format error;"; - } else { - propertyDescriptor->set_ = std::move(obj); - } + + std::unique_ptr set; + ret = params.GetObject("set", &set); + if (ret == Result::SUCCESS) { + obj = RemoteObject::Create(*set); + if (obj == nullptr) { + error += "'set' format error;"; } else { - error += "'set' should be an Object;"; + propertyDescriptor->set_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'set';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "configurable"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - propertyDescriptor->configurable_ = result->IsTrue(); - } else { - error += "'configurable' should be a Boolean;"; - } - } else { - error += "should contain 'configurable';"; + + bool configurable; + ret = params.GetBool("configurable", &configurable); + if (ret == Result::SUCCESS) { + propertyDescriptor->configurable_ = configurable; + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'configurable';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "enumerable"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - propertyDescriptor->enumerable_ = result->IsTrue(); - } else { - error += "'enumerable' should be a Boolean;"; - } - } else { - error += "should contain 'enumerable';"; + + bool enumerable; + ret = params.GetBool("enumerable", &enumerable); + if (ret == Result::SUCCESS) { + propertyDescriptor->enumerable_ = enumerable; + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'enumerable';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "wasThrown"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - propertyDescriptor->wasThrown_ = result->IsTrue(); - } else { - error += "'wasThrown' should be a Boolean;"; - } + + bool wasThrown; + ret = params.GetBool("wasThrown", &wasThrown); + if (ret == Result::SUCCESS) { + propertyDescriptor->wasThrown_ = wasThrown; + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'wasThrown';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "isOwn"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsBoolean()) { - propertyDescriptor->isOwn_ = result->IsTrue(); - } else { - error += "'isOwn' should be a Boolean;"; - } + + bool isOwn; + ret = params.GetBool("isOwn", &isOwn); + if (ret == Result::SUCCESS) { + propertyDescriptor->isOwn_ = isOwn; + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'isOwn';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "symbol"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'symbol' format error;"; - } else { - propertyDescriptor->symbol_ = std::move(obj); - } + + std::unique_ptr symbol; + ret = params.GetObject("symbol", &symbol); + if (ret == Result::SUCCESS) { + obj = RemoteObject::Create(*symbol); + if (obj == nullptr) { + error += "'symbol' format error;"; } else { - error += "'symbol' should be an Object;"; + propertyDescriptor->symbol_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'symbol';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "PropertyDescriptor::Create " << error; return nullptr; @@ -879,92 +840,63 @@ std::unique_ptr PropertyDescriptor::Create(const EcmaVM *ecm return propertyDescriptor; } -Local PropertyDescriptor::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr PropertyDescriptor::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "name")), - Local(StringRef::NewFromUtf8(ecmaVm, name_.c_str()))); + result->Add("name", name_.c_str()); if (value_) { ASSERT(value_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "value")), - Local(value_.value()->ToObject(ecmaVm))); + result->Add("value", value_.value()->ToJson()); } if (writable_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "writable")), - BooleanRef::New(ecmaVm, writable_.value())); + result->Add("writable", writable_.value()); } if (get_) { ASSERT(get_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "get")), - Local(get_.value()->ToObject(ecmaVm))); + result->Add("get", get_.value()->ToJson()); } if (set_) { ASSERT(set_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "set")), - Local(set_.value()->ToObject(ecmaVm))); - } - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "configurable")), - BooleanRef::New(ecmaVm, configurable_)); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "enumerable")), - BooleanRef::New(ecmaVm, enumerable_)); + result->Add("set", set_.value()->ToJson()); + } + result->Add("configurable", configurable_); + result->Add("enumerable", enumerable_); if (wasThrown_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "wasThrown")), - BooleanRef::New(ecmaVm, wasThrown_.value())); + result->Add("wasThrown", wasThrown_.value()); } if (isOwn_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "isOwn")), - BooleanRef::New(ecmaVm, isOwn_.value())); + result->Add("isOwn", isOwn_.value()); } if (symbol_) { ASSERT(symbol_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "symbol")), - Local(symbol_.value()->ToObject(ecmaVm))); + result->Add("symbol", symbol_.value()->ToJson()); } - return params; + return result; } -std::unique_ptr CallArgument::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr CallArgument::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "CallArgument::Create params is nullptr"; - return nullptr; - } - CString error; auto callArgument = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "value"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - callArgument->value_ = result; + std::string unserializableValue; + ret = params.GetString("unserializableValue", &unserializableValue); + if (ret == Result::SUCCESS) { + callArgument->unserializableValue_ = std::move(unserializableValue); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'unserializableValue';"; } - result = Local(params)->Get(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "unserializableValue"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - callArgument->unserializableValue_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'unserializableValue' should be a String;"; - } - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "objectId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - callArgument->objectId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'objectId' should be a String;"; - } + std::string objectId; + ret = params.GetString("objectId", &objectId); + if (ret == Result::SUCCESS) { + callArgument->objectId_ = std::stoi(objectId); + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'objectId';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "CallArgument::Create " << error; return nullptr; @@ -973,65 +905,48 @@ std::unique_ptr CallArgument::Create(const EcmaVM *ecmaVm, const L return callArgument; } -Local CallArgument::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr CallArgument::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - if (value_) { - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "value")), value_.value()); - } if (unserializableValue_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "unserializableValue")), - Local(StringRef::NewFromUtf8(ecmaVm, unserializableValue_->c_str()))); + result->Add("unserializableValue", unserializableValue_->c_str()); } if (objectId_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "objectId")), - Local(StringRef::NewFromUtf8(ecmaVm, objectId_->c_str()))); + result->Add("objectId", std::to_string(objectId_.value()).c_str()); } - return params; + return result; } -std::unique_ptr Location::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr Location::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "Location::Create params is nullptr"; - return nullptr; - } - CString error; auto location = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - location->scriptId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptId' should be a String;"; - } + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + location->scriptId_ = std::stoi(scriptId); } else { - error += "should contain 'scriptId';"; + error += "Unknown 'scriptId';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - location->line_ = static_cast(Local(result)->Value()); - } else { - error += "'lineNumber' should be a Number;"; - } + int32_t lineNumber; + ret = params.GetInt("lineNumber", &lineNumber); + if (ret == Result::SUCCESS) { + location->lineNumber_ = lineNumber; } else { - error += "should contain 'lineNumber';"; + error += "Unknown 'lineNumber';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - location->column_ = static_cast(Local(result)->Value()); - } else { - error += "'columnNumber' should be a Number;"; - } + int32_t columnNumber; + ret = params.GetInt("columnNumber", &columnNumber); + if (ret == Result::SUCCESS) { + location->columnNumber_ = columnNumber; + } else if (ret == Result::TYPE_ERROR) { // optional value + error += "Unknown 'columnNumber';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "Location::Create " << error; return nullptr; @@ -1040,54 +955,40 @@ std::unique_ptr Location::Create(const EcmaVM *ecmaVm, const Local Location::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr Location::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptId")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptId_.c_str()))); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber")), - IntegerRef::New(ecmaVm, line_)); - if (column_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber")), - IntegerRef::New(ecmaVm, column_.value())); + result->Add("scriptId", std::to_string(scriptId_).c_str()); + result->Add("lineNumber", lineNumber_); + if (columnNumber_) { + result->Add("columnNumber", columnNumber_.value()); } - return params; + return result; } -std::unique_ptr ScriptPosition::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr ScriptPosition::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "ScriptPosition::Create params is nullptr"; - return nullptr; - } - CString error; auto scriptPosition = std::make_unique(); + std::string error; + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptPosition->line_ = static_cast(Local(result)->Value()); - } else { - error += "'lineNumber' should be a Number;"; - } + int32_t lineNumber; + ret = params.GetInt("lineNumber", &lineNumber); + if (ret == Result::SUCCESS) { + scriptPosition->lineNumber_ = lineNumber; } else { - error += "should contain 'lineNumber';"; + error += "Unknown 'lineNumber';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - scriptPosition->column_ = static_cast(Local(result)->Value()); - } else { - error += "'columnNumber' should be a Number;"; - } + int32_t columnNumber; + ret = params.GetInt("columnNumber", &columnNumber); + if (ret == Result::SUCCESS) { + scriptPosition->columnNumber_ = columnNumber; } else { - error += "should contain 'columnNumber';"; + error += "Unknown 'columnNumber';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "ScriptPosition::Create " << error; return nullptr; @@ -1096,48 +997,36 @@ std::unique_ptr ScriptPosition::Create(const EcmaVM *ecmaVm, con return scriptPosition; } -Local ScriptPosition::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr ScriptPosition::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber")), - IntegerRef::New(ecmaVm, line_)); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber")), - IntegerRef::New(ecmaVm, column_)); + result->Add("lineNumber", lineNumber_); + result->Add("columnNumber", columnNumber_); - return params; + return result; } -std::unique_ptr SearchMatch::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr SearchMatch::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "SearchMatch::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto locationSearch = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - locationSearch->lineNumber_ = static_cast(Local(result)->Value()); - } else { - error += "'lineNumber' should be a Number;"; - } + int32_t lineNumber; + ret = params.GetInt("lineNumber", &lineNumber); + if (ret == Result::SUCCESS) { + locationSearch->lineNumber_ = lineNumber; } else { - error += "should contain 'lineNumber';"; + error += "Unknown 'lineNumber';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineContent"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - locationSearch->lineContent_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'lineContent' should be a String;"; - } + std::string lineContent; + ret = params.GetString("lineContent", &lineContent); + if (ret == Result::SUCCESS) { + locationSearch->lineContent_ = std::move(lineContent); } else { - error += "should contain 'lineContent';"; + error += "Unknown 'lineContent';"; } if (!error.empty()) { @@ -1148,68 +1037,57 @@ std::unique_ptr SearchMatch::Create(const EcmaVM *ecmaVm, const Loc return locationSearch; } -Local SearchMatch::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr SearchMatch::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber")), - IntegerRef::New(ecmaVm, lineNumber_)); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "lineContent")), - Local(StringRef::NewFromUtf8(ecmaVm, lineContent_.c_str()))); - return params; + result->Add("lineNumber", lineNumber_); + result->Add("lineContent", lineContent_.c_str()); + + return result; } -std::unique_ptr LocationRange::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr LocationRange::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "BreakLocation::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto locationRange = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - locationRange->scriptId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptId' should be a String;"; - } + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + locationRange->scriptId_ = std::stoi(scriptId); } else { - error += "should contain 'scriptId';"; + error += "Unknown 'scriptId';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "start"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = ScriptPosition::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'start' format error;"; - } else { - locationRange->start_ = std::move(obj); - } + + std::unique_ptr start; + std::unique_ptr obj; + ret = params.GetObject("start", &start); + if (ret == Result::SUCCESS) { + obj = ScriptPosition::Create(*start); + if (obj == nullptr) { + error += "'start' format error;"; } else { - error += "'start' should be an Object;"; + locationRange->start_ = std::move(obj); } } else { - error += "should contain 'start';"; + error += "Unknown 'start';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "end"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = ScriptPosition::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'end' format error;"; - } else { - locationRange->end_ = std::move(obj); - } + + std::unique_ptr end; + ret = params.GetObject("end", &end); + if (ret == Result::SUCCESS) { + obj = ScriptPosition::Create(*end); + if (obj == nullptr) { + error += "'end' format error;"; } else { - error += "'end' should be an Object;"; + locationRange->end_ = std::move(obj); } } else { - error += "should contain 'end';"; + error += "Unknown 'end';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "LocationRange::Create " << error; return nullptr; @@ -1218,75 +1096,61 @@ std::unique_ptr LocationRange::Create(const EcmaVM *ecmaVm, const return locationRange; } -Local LocationRange::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr LocationRange::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptId")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptId_.c_str()))); + result->Add("scriptId", std::to_string(scriptId_).c_str()); ASSERT(start_ != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "object")), - Local(start_->ToObject(ecmaVm))); + result->Add("start", start_->ToJson()); ASSERT(end_ != nullptr); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "object")), - Local(end_->ToObject(ecmaVm))); + result->Add("end", end_->ToJson()); - return params; + return result; } -std::unique_ptr BreakLocation::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr BreakLocation::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "BreakLocation::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto breakLocation = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scriptId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - breakLocation->scriptId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'scriptId' should be a String;"; - } + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + breakLocation->scriptId_ = std::stoi(scriptId); } else { - error += "should contain 'scriptId';"; + error += "Unknown 'scriptId';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - breakLocation->line_ = static_cast(Local(result)->Value()); - } else { - error += "'lineNumber' should be a Number;"; - } + + int32_t lineNumber; + ret = params.GetInt("lineNumber", &lineNumber); + if (ret == Result::SUCCESS) { + breakLocation->lineNumber_ = lineNumber; } else { - error += "should contain 'lineNumber';"; + error += "Unknown 'lineNumber';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsNumber()) { - breakLocation->column_ = static_cast(Local(result)->Value()); - } else { - error += "'columnNumber' should be a Number;"; - } + + int32_t columnNumber; + ret = params.GetInt("columnNumber", &columnNumber); + if (ret == Result::SUCCESS) { + breakLocation->columnNumber_ = columnNumber; + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'columnNumber';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "type"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - auto type = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - if (BreakType::Valid(type)) { - breakLocation->type_ = type; - } else { - error += "'type' is invalid;"; - } + + std::string type; + ret = params.GetString("type", &type); + if (ret == Result::SUCCESS) { + if (BreakType::Valid(type)) { + breakLocation->type_ = std::move(type); } else { - error += "'type' should be a String;"; + error += "'type' is invalid;"; } + } else if (ret == Result::TYPE_ERROR) { + error += "type 'scriptId';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "Location::Create " << error; return nullptr; @@ -1295,103 +1159,89 @@ std::unique_ptr BreakLocation::Create(const EcmaVM *ecmaVm, const return breakLocation; } -Local BreakLocation::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr BreakLocation::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "scriptId")), - Local(StringRef::NewFromUtf8(ecmaVm, scriptId_.c_str()))); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "lineNumber")), - IntegerRef::New(ecmaVm, line_)); - if (column_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "columnNumber")), - IntegerRef::New(ecmaVm, column_.value())); + result->Add("scriptId", std::to_string(scriptId_).c_str()); + result->Add("lineNumber", lineNumber_); + if (columnNumber_) { + result->Add("columnNumber", columnNumber_.value()); } if (type_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "type")), - Local(StringRef::NewFromUtf8(ecmaVm, type_->c_str()))); + result->Add("type", type_->c_str()); } - return params; + return result; } -std::unique_ptr Scope::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr Scope::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "Scope::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto scope = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "type"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - auto type = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - if (Scope::Type::Valid(type)) { - scope->type_ = type; - } else { - error += "'type' is invalid;"; - } + std::string type; + ret = params.GetString("type", &type); + if (ret == Result::SUCCESS) { + if (Scope::Type::Valid(type)) { + scope->type_ = std::move(type); } else { - error += "'type' should be a String;"; + error += "'type' is invalid;"; } } else { - error += "should contain 'type';"; + error += "Unknown 'type';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "object"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'object' format error;"; - } else { - scope->object_ = std::move(obj); - } + + std::unique_ptr object; + std::unique_ptr remoteObject; + ret = params.GetObject("object", &object); + if (ret == Result::SUCCESS) { + remoteObject = RemoteObject::Create(*object); + if (remoteObject == nullptr) { + error += "'object' format error;"; } else { - error += "'object' should be an Object;"; + scope->object_ = std::move(remoteObject); } } else { - error += "should contain 'object';"; + error += "Unknown 'object';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "name"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - scope->name_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'name' should be a String;"; - } + + std::string name; + ret = params.GetString("name", &name); + if (ret == Result::SUCCESS) { + scope->name_ = std::move(name); + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'name';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "startLocation"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = Location::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'startLocation' format error;"; - } else { - scope->startLocation_ = std::move(obj); - } + + std::unique_ptr startLocation; + std::unique_ptr obj; + ret = params.GetObject("startLocation", &startLocation); + if (ret == Result::SUCCESS) { + obj = Location::Create(*startLocation); + if (obj == nullptr) { + error += "'startLocation' format error;"; } else { - error += "'startLocation' should be an Object;"; + scope->startLocation_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'startLocation';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "endLocation"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = Location::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'endLocation' format error;"; - } else { - scope->endLocation_ = std::move(obj); - } + + std::unique_ptr endLocation; + ret = params.GetObject("endLocation", &endLocation); + if (ret == Result::SUCCESS) { + obj = Location::Create(*endLocation); + if (obj == nullptr) { + error += "'endLocation' format error;"; } else { - error += "'endLocation' should be an Object;"; + scope->endLocation_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'endLocation';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "Location::Create " << error; return nullptr; @@ -1400,156 +1250,130 @@ std::unique_ptr Scope::Create(const EcmaVM *ecmaVm, const Local Scope::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr Scope::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "type")), - Local(StringRef::NewFromUtf8(ecmaVm, type_.c_str()))); + result->Add("type", type_.c_str()); ASSERT(object_ != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "object")), - Local(object_->ToObject(ecmaVm))); + result->Add("object", object_->ToJson()); if (name_) { - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "name")), - Local(StringRef::NewFromUtf8(ecmaVm, name_->c_str()))); + result->Add("name", name_->c_str()); } if (startLocation_) { ASSERT(startLocation_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "startLocation")), - Local(startLocation_.value()->ToObject(ecmaVm))); + result->Add("startLocation", startLocation_.value()->ToJson()); } if (endLocation_) { ASSERT(endLocation_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "endLocation")), - Local(endLocation_.value()->ToObject(ecmaVm))); + result->Add("endLocation", endLocation_.value()->ToJson()); } - return params; + return result; } -std::unique_ptr CallFrame::Create(const EcmaVM *ecmaVm, const Local ¶ms) +std::unique_ptr CallFrame::Create(const PtJson ¶ms) { - if (params.IsEmpty() || !params->IsObject()) { - LOG(ERROR, DEBUGGER) << "CallFrame::Create params is nullptr"; - return nullptr; - } - CString error; + std::string error; auto callFrame = std::make_unique(); + Result ret; - Local result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "callFrameId"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - callFrame->callFrameId_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'callFrameId' should be a String;"; - } + std::string callFrameId; + ret = params.GetString("callFrameId", &callFrameId); + if (ret == Result::SUCCESS) { + callFrame->callFrameId_ = std::stoi(callFrameId); } else { - error += "should contain 'callFrameId';"; + error += "Unknown 'callFrameId';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "functionName"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - callFrame->functionName_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'functionName' should be a String;"; - } + + std::string functionName; + ret = params.GetString("functionName", &functionName); + if (ret == Result::SUCCESS) { + callFrame->functionName_ = std::move(functionName); } else { - error += "should contain 'functionName';"; + error += "Unknown 'functionName';"; } - result = - Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "functionLocation"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = Location::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'functionLocation' format error;"; - } else { - callFrame->functionLocation_ = std::move(obj); - } + + std::unique_ptr functionLocation; + std::unique_ptr obj; + ret = params.GetObject("functionLocation", &functionLocation); + if (ret == Result::SUCCESS) { + obj = Location::Create(*functionLocation); + if (obj == nullptr) { + error += "'functionLocation' format error;"; } else { - error += "'functionLocation' should be an Object;"; + callFrame->functionLocation_ = std::move(obj); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'functionLocation';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "location"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = Location::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'location' format error;"; - } else { - callFrame->location_ = std::move(obj); - } + + std::unique_ptr location; + ret = params.GetObject("location", &location); + if (ret == Result::SUCCESS) { + obj = Location::Create(*location); + if (obj == nullptr) { + error += "'location' format error;"; } else { - error += "'location' should be an Object;"; + callFrame->location_ = std::move(obj); } } else { - error += "should contain 'location';"; + error += "Unknown 'location';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "url"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsString()) { - callFrame->url_ = DebuggerApi::ConvertToString(StringRef::Cast(*result)->ToString()); - } else { - error += "'url' should be a String;"; - } + + std::string url; + ret = params.GetString("url", &url); + if (ret == Result::SUCCESS) { + callFrame->url_ = std::move(url); } else { - error += "should contain 'url';"; - } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scopeChain"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsArray(ecmaVm)) { - auto array = Local(result); - uint32_t len = array->Length(ecmaVm); - Local key = JSValueRef::Undefined(ecmaVm); - for (uint32_t i = 0; i < len; ++i) { - key = IntegerRef::New(ecmaVm, i); - Local resultValue = Local(array)->Get(ecmaVm, key->ToString(ecmaVm)); - std::unique_ptr scope = Scope::Create(ecmaVm, resultValue); - if (resultValue.IsEmpty() || scope == nullptr) { - error += "'scopeChain' format invalid;"; - } + error += "Unknown 'url';"; + } + + std::unique_ptr scopeChain; + ret = params.GetArray("scopeChain", &scopeChain); + if (ret == Result::SUCCESS) { + int32_t len = scopeChain->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr arrayEle = scopeChain->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr scope = Scope::Create(*arrayEle); + if (scope == nullptr) { + error += "'scopeChain' format error;"; + } else { callFrame->scopeChain_.emplace_back(std::move(scope)); } - } else { - error += "'scopeChain' should be an Array;"; } } else { - error += "should contain 'scopeChain';"; + error += "Unknown 'scopeChain';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "this"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'this' format error;"; - } else { - callFrame->this_ = std::move(obj); - } + + std::unique_ptr thisObj; + std::unique_ptr remoteObject; + ret = params.GetObject("this", &thisObj); + if (ret == Result::SUCCESS) { + remoteObject = RemoteObject::Create(*thisObj); + if (remoteObject == nullptr) { + error += "'this' format error;"; } else { - error += "'this' should be an Object;"; + callFrame->this_ = std::move(remoteObject); } } else { - error += "should contain 'this';"; + error += "Unknown 'this';"; } - result = Local(params)->Get(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "returnValue"))); - if (!result.IsEmpty() && !result->IsUndefined()) { - if (result->IsObject()) { - std::unique_ptr obj = RemoteObject::Create(ecmaVm, result); - if (obj == nullptr) { - error += "'returnValue' format error;"; - } else { - callFrame->returnValue_ = std::move(obj); - } + + std::unique_ptr returnValue; + ret = params.GetObject("returnValue", &returnValue); + if (ret == Result::SUCCESS) { + remoteObject = RemoteObject::Create(*returnValue); + if (remoteObject == nullptr) { + error += "'returnValue' format error;"; } else { - error += "'returnValue' should be an Object;"; + callFrame->returnValue_ = std::move(remoteObject); } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'returnValue';"; } + if (!error.empty()) { LOG(ERROR, DEBUGGER) << "CallFrame::Create " << error; return nullptr; @@ -1558,46 +1382,948 @@ std::unique_ptr CallFrame::Create(const EcmaVM *ecmaVm, const Local CallFrame::ToObject(const EcmaVM *ecmaVm) +std::unique_ptr CallFrame::ToJson() const { - Local params = NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("callFrameId", std::to_string(callFrameId_).c_str()); + result->Add("functionName", functionName_.c_str()); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "callFrameId")), - Local(StringRef::NewFromUtf8(ecmaVm, callFrameId_.c_str()))); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "functionName")), - Local(StringRef::NewFromUtf8(ecmaVm, functionName_.c_str()))); if (functionLocation_) { ASSERT(functionLocation_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "functionLocation")), - Local(functionLocation_.value()->ToObject(ecmaVm))); + result->Add("functionLocation", functionLocation_.value()->ToJson()); } ASSERT(location_ != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "location")), - Local(location_->ToObject(ecmaVm))); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "url")), - Local(StringRef::NewFromUtf8(ecmaVm, url_.c_str()))); + result->Add("location", location_->ToJson()); + result->Add("url", url_.c_str()); + size_t len = scopeChain_.size(); - Local values = ArrayRef::New(ecmaVm, len); + std::unique_ptr values = PtJson::CreateArray(); for (size_t i = 0; i < len; i++) { - Local scope = scopeChain_[i]->ToObject(ecmaVm); - values->Set(ecmaVm, i, scope); + std::unique_ptr scope = scopeChain_[i]->ToJson(); + values->Push(scope); } - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "scopeChain")), values); + result->Add("scopeChain", values); + ASSERT(this_ != nullptr); - params->Set(ecmaVm, Local(StringRef::NewFromUtf8(ecmaVm, "this")), - Local(this_->ToObject(ecmaVm))); + result->Add("this", this_->ToJson()); if (returnValue_) { ASSERT(returnValue_.value() != nullptr); - params->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "returnValue")), - Local(returnValue_.value()->ToObject(ecmaVm))); + result->Add("returnValue", returnValue_.value()->ToJson()); + } + + return result; +} + +#ifdef SUPPORT_PROFILER_CDP +std::unique_ptr SamplingHeapProfileSample::Create(const PtJson ¶ms) +{ + std::string error; + auto samplingHeapProfileSample = std::make_unique(); + Result ret; + + int32_t size; + ret = params.GetInt("size", &size); + if (ret == Result::SUCCESS) { + samplingHeapProfileSample->size_ = size; + } else { + error += "Unknown 'size';"; + } + int32_t nodeId; + ret = params.GetInt("nodeId", &nodeId); + if (ret == Result::SUCCESS) { + samplingHeapProfileSample->nodeId_ = nodeId; + } else { + error += "Unknown 'nodeId';"; + } + int32_t ordinal; + ret = params.GetInt("ordinal", &ordinal); + if (ret == Result::SUCCESS) { + samplingHeapProfileSample->ordinal_ = ordinal; + } else { + error += "Unknown 'ordinal';"; + } + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "SamplingHeapProfileSample::Create " << error; + return nullptr; + } + + return samplingHeapProfileSample; +} + +std::unique_ptr SamplingHeapProfileSample::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("size", size_); + result->Add("nodeId", nodeId_); + result->Add("ordinal", ordinal_); + + return result; +} + +std::unique_ptr RuntimeCallFrame::Create(const PtJson ¶ms) +{ + std::string error; + auto runtimeCallFrame = std::make_unique(); + Result ret; + + std::string functionName; + ret = params.GetString("functionName", &functionName); + if (ret == Result::SUCCESS) { + runtimeCallFrame->functionName_ = std::move(functionName); + } else { + error += "Unknown 'functionName';"; } - return params; + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + runtimeCallFrame->scriptId_ = std::move(scriptId); + } else { + error += "Unknown 'scriptId';"; + } + + std::string url; + ret = params.GetString("url", &url); + if (ret == Result::SUCCESS) { + runtimeCallFrame->url_ = std::move(url); + } else { + error += "Unknown 'url';"; + } + + int32_t lineNumber; + ret = params.GetInt("lineNumber", &lineNumber); + if (ret == Result::SUCCESS) { + runtimeCallFrame->lineNumber_ = lineNumber; + } else { + error += "Unknown 'lineNumber';"; + } + + int32_t columnNumber; + ret = params.GetInt("columnNumber", &columnNumber); + if (ret == Result::SUCCESS) { + runtimeCallFrame->columnNumber_ = columnNumber; + } else { + error += "Unknown 'columnNumber';"; + } + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "RuntimeCallFrame::Create " << error; + return nullptr; + } + + return runtimeCallFrame; +} + +std::unique_ptr RuntimeCallFrame::FromFrameInfo(const FrameInfo &cpuFrameInfo) +{ + auto runtimeCallFrame = std::make_unique(); + runtimeCallFrame->SetFunctionName(cpuFrameInfo.functionName); + runtimeCallFrame->SetScriptId(std::to_string(cpuFrameInfo.scriptId)); + runtimeCallFrame->SetColumnNumber(cpuFrameInfo.columnNumber); + runtimeCallFrame->SetLineNumber(cpuFrameInfo.lineNumber); + runtimeCallFrame->SetUrl(cpuFrameInfo.url); + return runtimeCallFrame; +} + +std::unique_ptr RuntimeCallFrame::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("functionName", functionName_.c_str()); + result->Add("scriptId", scriptId_.c_str()); + result->Add("url", url_.c_str()); + result->Add("lineNumber", lineNumber_); + result->Add("columnNumber", columnNumber_); + + return result; +} + +std::unique_ptr SamplingHeapProfileNode::Create(const PtJson ¶ms) +{ + std::string error; + auto samplingHeapProfileNode = std::make_unique(); + Result ret; + + std::unique_ptr callFrame; + ret = params.GetObject("callFrame", &callFrame); + if (ret == Result::SUCCESS) { + std::unique_ptr runtimeCallFrame = RuntimeCallFrame::Create(*callFrame); + if (runtimeCallFrame == nullptr) { + error += "'callFrame' format invalid;"; + } else { + samplingHeapProfileNode->callFrame_ = std::move(runtimeCallFrame); + } + } else { + error += "Unknown 'callFrame';"; + } + + int32_t selfSize; + ret = params.GetInt("selfSize", &selfSize); + if (ret == Result::SUCCESS) { + samplingHeapProfileNode->selfSize_ = selfSize; + } else { + error += "Unknown 'selfSize';"; + } + + int32_t id; + ret = params.GetInt("id", &id); + if (ret == Result::SUCCESS) { + samplingHeapProfileNode->id_ = id; + } else { + error += "Unknown 'id';"; + } + + std::unique_ptr children; + ret = params.GetArray("children", &children); + if (ret == Result::SUCCESS) { + int32_t len = children->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr arrayEle = children->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr node = SamplingHeapProfileNode::Create(*arrayEle); + if (node == nullptr) { + error += "'children' format invalid;"; + } else { + samplingHeapProfileNode->children_.emplace_back(std::move(node)); + } + } + } else { + error += "Unknown 'children';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "SamplingHeapProfileNode::Create " << error; + return nullptr; + } + + return samplingHeapProfileNode; +} + +std::unique_ptr SamplingHeapProfileNode::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + ASSERT(callFrame_ != nullptr); + result->Add("callFrame", callFrame_->ToJson()); + result->Add("selfSize", selfSize_); + result->Add("id", id_); + + std::unique_ptr childrens = PtJson::CreateArray(); + size_t len = children_.size(); + for (size_t i = 0; i < len; i++) { + childrens->Push(children_[i]->ToJson()); + } + result->Add("children", childrens); + + return result; +} + +std::unique_ptr SamplingHeapProfile::Create(const PtJson ¶ms) +{ + std::string error; + auto samplingHeapProfile = std::make_unique(); + Result ret; + + std::unique_ptr head; + ret = params.GetObject("head", &head); + if (ret == Result::SUCCESS) { + std::unique_ptr pHead = SamplingHeapProfileNode::Create(*head); + if (pHead == nullptr) { + error += "'sample' format invalid;"; + } else { + samplingHeapProfile->head_ = std::move(pHead); + } + } else { + error += "Unknown 'head';"; + } + + std::unique_ptr samples; + ret = params.GetArray("samples", &samples); + if (ret == Result::SUCCESS) { + int32_t len = samples->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr arrayEle = samples->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr pSample = SamplingHeapProfileSample::Create(*arrayEle); + if (pSample == nullptr) { + error += "'sample' format invalid;"; + } else { + samplingHeapProfile->samples_.emplace_back(std::move(pSample)); + } + } + } else { + error += "Unknown 'samples';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "SamplingHeapProfile::Create " << error; + return nullptr; + } + + return samplingHeapProfile; +} + +std::unique_ptr SamplingHeapProfile::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + ASSERT(head_ != nullptr); + result->Add("head", head_->ToJson()); + + std::unique_ptr samples = PtJson::CreateArray(); + size_t len = samples_.size(); + for (size_t i = 0; i < len; i++) { + ASSERT(samples_[i] != nullptr); + samples->Push(samples_[i]->ToJson()); + } + result->Add("samples", samples); + return result; +} + +std::unique_ptr PositionTickInfo::Create(const PtJson ¶ms) +{ + std::string error; + auto positionTickInfo = std::make_unique(); + Result ret; + + int32_t line; + ret = params.GetInt("line", &line); + if (ret == Result::SUCCESS) { + positionTickInfo->line_ = line; + } else { + error += "Unknown 'line';"; + } + + int32_t ticks; + ret = params.GetInt("ticks", &ticks); + if (ret == Result::SUCCESS) { + positionTickInfo->ticks_ = ticks; + } else { + error += "Unknown 'ticks';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "PositionTickInfo::Create " << error; + return nullptr; + } + + return positionTickInfo; +} + +std::unique_ptr PositionTickInfo::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("line", line_); + result->Add("ticks", ticks_); + + return result; +} + +std::unique_ptr ProfileNode::Create(const PtJson ¶ms) +{ + std::string error; + auto profileNode = std::make_unique(); + Result ret; + + int32_t id; + ret = params.GetInt("id", &id); + if (ret == Result::SUCCESS) { + profileNode->id_ = id; + } else { + error += "Unknown 'id';"; + } + + std::unique_ptr callFrame; + ret = params.GetObject("callFrame", &callFrame); + if (ret == Result::SUCCESS) { + std::unique_ptr runtimeCallFrame = RuntimeCallFrame::Create(*callFrame); + if (runtimeCallFrame == nullptr) { + error += "'callFrame' format invalid;"; + } else { + profileNode->callFrame_ = std::move(runtimeCallFrame); + } + } else { + error += "Unknown 'callFrame';"; + } + + int32_t hitCount; + ret = params.GetInt("hitCount", &hitCount); + if (ret == Result::SUCCESS) { + profileNode->hitCount_ = hitCount; + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'hitCount';"; + } + + std::unique_ptr children; + ret = params.GetArray("children", &children); + if (ret == Result::SUCCESS) { + int32_t childrenLen = children->GetSize(); + for (int32_t i = 0; i < childrenLen; ++i) { + int32_t pChildren = children->Get(i)->GetInt(); + profileNode->children_.value().emplace_back(pChildren); + } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'children';"; + } + + std::unique_ptr positionTicks; + ret = params.GetArray("positionTicks", &positionTicks); + if (ret == Result::SUCCESS) { + int32_t positionTicksLen = positionTicks->GetSize(); + for (int32_t i = 0; i < positionTicksLen; ++i) { + std::unique_ptr arrayEle = positionTicks->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr tmpPositionTicks = PositionTickInfo::Create(*arrayEle); + if (tmpPositionTicks == nullptr) { + error += "'positionTicks' format invalid;"; + } else { + profileNode->positionTicks_.value().emplace_back(std::move(tmpPositionTicks)); + } + } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'positionTicks';"; + } + + std::string deoptReason; + ret = params.GetString("deoptReason", &deoptReason); + if (ret == Result::SUCCESS) { + profileNode->deoptReason_ = std::move(deoptReason); + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'deoptReason';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "ProfileNode::Create " << error; + return nullptr; + } + + return profileNode; +} + +std::unique_ptr ProfileNode::FromCpuProfileNode(const CpuProfileNode &cpuProfileNode) +{ + auto profileNode = std::make_unique(); + profileNode->SetId(cpuProfileNode.id); + profileNode->SetHitCount(cpuProfileNode.hitCount); + + size_t childrenLen = cpuProfileNode.children.size(); + std::vector tmpChildren; + tmpChildren.reserve(childrenLen); + for (size_t i = 0; i < childrenLen; ++i) { + tmpChildren.push_back(cpuProfileNode.children[i]); + } + profileNode->SetChildren(tmpChildren); + profileNode->SetCallFrame(RuntimeCallFrame::FromFrameInfo(cpuProfileNode.codeEntry)); + return profileNode; +} + +std::unique_ptr ProfileNode::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("id", id_); + ASSERT(callFrame_ != nullptr); + result->Add("callFrame", callFrame_->ToJson()); + if (hitCount_) { + result->Add("hitCount", hitCount_.value()); + } + if (children_) { + std::unique_ptr childrens = PtJson::CreateArray(); + size_t len = children_->size(); + for (size_t i = 0; i < len; i++) { + childrens->Push(children_.value()[i]); + } + result->Add("children", childrens); + } + if (positionTicks_) { + std::unique_ptr positionTicks = PtJson::CreateArray(); + size_t len = positionTicks_->size(); + for (size_t i = 0; i < len; i++) { + ASSERT(positionTicks_.value()[i] != nullptr); + positionTicks->Push(positionTicks_.value()[i]->ToJson()); + } + result->Add("positionTicks", positionTicks); + } + + if (deoptReason_) { + result->Add("deoptReason", deoptReason_.value().c_str()); + } + + return result; +} + +std::unique_ptr Profile::Create(const PtJson ¶ms) +{ + std::string error; + auto profile = std::make_unique(); + Result ret; + + std::unique_ptr nodes; + ret = params.GetArray("nodes", &nodes); + if (ret == Result::SUCCESS) { + int32_t nodesLen = nodes->GetSize(); + for (int32_t i = 0; i < nodesLen; ++i) { + std::unique_ptr arrayEle = nodes->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr profileNode = ProfileNode::Create(*arrayEle); + if (profileNode == nullptr) { + error += "'nodes' format invalid;"; + } else { + profile->nodes_.emplace_back(std::move(profileNode)); + } + } + } else { + error += "Unknown 'nodes';"; + } + + int64_t startTime; + ret = params.GetInt64("startTime", &startTime); + if (ret == Result::SUCCESS) { + profile->startTime_ = startTime; + } else { + error += "Unknown 'startTime';"; + } + + int64_t endTime; + ret = params.GetInt64("endTime", &endTime); + if (ret == Result::SUCCESS) { + profile->endTime_ = endTime; + } else { + error += "Unknown 'endTime';"; + } + + std::unique_ptr samples; + ret = params.GetArray("samples", &samples); + if (ret == Result::SUCCESS) { + int32_t samplesLen = samples->GetSize(); + for (int32_t i = 0; i < samplesLen; ++i) { + int32_t pSamples = samples->Get(i)->GetInt(); + profile->samples_.value().emplace_back(pSamples); + } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'samples';"; + } + + std::unique_ptr timeDeltas; + ret = params.GetArray("timeDeltas", &timeDeltas); + if (ret == Result::SUCCESS) { + int32_t timeDeltasLen = timeDeltas->GetSize(); + for (int32_t i = 0; i < timeDeltasLen; ++i) { + int32_t pTimeDeltas = timeDeltas->Get(i)->GetInt(); + profile->timeDeltas_.value().emplace_back(pTimeDeltas); + } + } else if (ret == Result::TYPE_ERROR) { + error += "Unknown 'timeDeltas';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "Profile::Create " << error; + return nullptr; + } + + return profile; +} + +std::unique_ptr Profile::FromProfileInfo(const ProfileInfo &profileInfo) +{ + auto profile = std::make_unique(); + profile->SetStartTime(static_cast(profileInfo.startTime)); + profile->SetEndTime(static_cast(profileInfo.stopTime)); + size_t samplesLen = profileInfo.samples.size(); + std::vector tmpSamples; + tmpSamples.reserve(samplesLen); + for (size_t i = 0; i < samplesLen; ++i) { + tmpSamples.push_back(profileInfo.samples[i]); + } + profile->SetSamples(tmpSamples); + + size_t timeDeltasLen = profileInfo.timeDeltas.size(); + std::vector tmpTimeDeltas; + tmpTimeDeltas.reserve(timeDeltasLen); + for (size_t i = 0; i < timeDeltasLen; ++i) { + tmpTimeDeltas.push_back(profileInfo.timeDeltas[i]); + } + profile->SetTimeDeltas(tmpTimeDeltas); + + std::vector> profileNode; + size_t nodesLen = profileInfo.nodes.size(); + for (size_t i = 0; i < nodesLen; ++i) { + const auto &cpuProfileNode = profileInfo.nodes[i]; + profileNode.push_back(ProfileNode::FromCpuProfileNode(cpuProfileNode)); + } + profile->SetNodes(std::move(profileNode)); + return profile; +} + +std::unique_ptr Profile::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("startTime", startTime_); + result->Add("endTime", endTime_); + + std::unique_ptr nodes = PtJson::CreateArray(); + size_t nodesLen = nodes_.size(); + for (size_t i = 0; i < nodesLen; i++) { + ASSERT(nodes_[i] != nullptr); + nodes->Push(nodes_[i]->ToJson()); + } + result->Add("nodes", nodes); + + if (samples_) { + std::unique_ptr samples = PtJson::CreateArray(); + size_t samplesLen = samples_->size(); + for (size_t i = 0; i < samplesLen; i++) { + samples->Push(samples_.value()[i]); + } + result->Add("samples", samples); + } + + if (timeDeltas_) { + std::unique_ptr timeDeltas = PtJson::CreateArray(); + size_t timeDeltasLen = timeDeltas_->size(); + for (size_t i = 0; i < timeDeltasLen; i++) { + timeDeltas->Push(timeDeltas_.value()[i]); + } + result->Add("timeDeltas", timeDeltas); + } + + return result; +} + +std::unique_ptr Coverage::Create(const PtJson ¶ms) +{ + std::string error; + auto coverage = std::make_unique(); + Result ret; + + int32_t startOffset; + ret = params.GetInt("startOffset", &startOffset); + if (ret == Result::SUCCESS) { + coverage->startOffset_ = startOffset; + } else { + error += "Unknown 'startOffset';"; + } + + int32_t endOffset; + ret = params.GetInt("endOffset", &endOffset); + if (ret == Result::SUCCESS) { + coverage->endOffset_ = endOffset; + } else { + error += "Unknown 'endOffset';"; + } + + int32_t count; + ret = params.GetInt("count", &count); + if (ret == Result::SUCCESS) { + coverage->count_ = count; + } else { + error += "Unknown 'count';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "Coverage::Create " << error; + return nullptr; + } + + return coverage; +} + +std::unique_ptr Coverage::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("startOffset", startOffset_); + result->Add("endOffset", endOffset_); + result->Add("count", count_); + + return result; +} + +std::unique_ptr FunctionCoverage::Create(const PtJson ¶ms) +{ + std::string error; + auto functionCoverage = std::make_unique(); + Result ret; + + std::string functionName; + ret = params.GetString("functionName", &functionName); + if (ret == Result::SUCCESS) { + functionCoverage->functionName_ = std::move(functionName); + } else { + error += "Unknown 'functionName';"; + } + + std::unique_ptr ranges; + ret = params.GetArray("ranges", &ranges); + if (ret == Result::SUCCESS) { + int32_t len = ranges->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr arrayEle = ranges->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr pRanges = Coverage::Create(*arrayEle); + if (pRanges == nullptr) { + error += "'ranges' format invalid;"; + } else { + functionCoverage->ranges_.emplace_back(std::move(pRanges)); + } + } + } else { + error += "Unknown 'ranges';"; + } + + bool isBlockCoverage; + ret = params.GetBool("isBlockCoverage", &isBlockCoverage); + if (ret == Result::SUCCESS) { + functionCoverage->isBlockCoverage_ = isBlockCoverage; + } else { + error += "Unknown 'isBlockCoverage';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "FunctionCoverage::Create " << error; + return nullptr; + } + + return functionCoverage; +} + +std::unique_ptr FunctionCoverage::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("functionName", functionName_.c_str()); + + std::unique_ptr ranges = PtJson::CreateArray(); + size_t len = ranges_.size(); + for (size_t i = 0; i < len; i++) { + ASSERT(ranges_[i] != nullptr); + ranges->Push(ranges_[i]->ToJson()); + } + result->Add("ranges", ranges); + + result->Add("isBlockCoverage", isBlockCoverage_); + + return result; +} + +std::unique_ptr ScriptCoverage::Create(const PtJson ¶ms) +{ + std::string error; + auto scriptCoverage = std::make_unique(); + Result ret; + + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + scriptCoverage->scriptId_ = std::move(scriptId); + } else { + error += "Unknown 'scriptId';"; + } + + std::string url; + ret = params.GetString("url", &url); + if (ret == Result::SUCCESS) { + scriptCoverage->url_ = std::move(url); + } else { + error += "Unknown 'url';"; + } + + std::unique_ptr functions; + ret = params.GetArray("functions", &functions); + if (ret == Result::SUCCESS) { + int32_t len = functions->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr arrayEle = functions->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr pFunctions = FunctionCoverage::Create(*arrayEle); + if (pFunctions == nullptr) { + error += "'functions' format invalid;"; + } else { + scriptCoverage->functions_.emplace_back(std::move(pFunctions)); + } + } + } else { + error += "Unknown 'functions';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "ScriptCoverage::Create " << error; + return nullptr; + } + + return scriptCoverage; +} + +std::unique_ptr ScriptCoverage::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("scriptId", scriptId_.c_str()); + result->Add("url", url_.c_str()); + + std::unique_ptr functions = PtJson::CreateArray(); + size_t len = functions_.size(); + for (size_t i = 0; i < len; i++) { + ASSERT(functions_[i] != nullptr); + functions->Push(functions_[i]->ToJson()); + } + result->Add("functions", functions); + + return result; +} + +std::unique_ptr TypeObject::Create(const PtJson ¶ms) +{ + std::string error; + auto typeObject = std::make_unique(); + Result ret; + + std::string name; + ret = params.GetString("name", &name); + if (ret == Result::SUCCESS) { + typeObject->name_ = std::move(name); + } else { + error += "Unknown 'name';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "TypeObject::Create " << error; + return nullptr; + } + + return typeObject; +} + +std::unique_ptr TypeObject::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("name", name_.c_str()); + + return result; +} + +std::unique_ptr TypeProfileEntry::Create(const PtJson ¶ms) +{ + std::string error; + auto typeProfileEntry = std::make_unique(); + Result ret; + + int32_t offset; + ret = params.GetInt("offset", &offset); + if (ret == Result::SUCCESS) { + typeProfileEntry->offset_ = offset; + } else { + error += "Unknown 'offset';"; + } + + std::unique_ptr types; + ret = params.GetArray("types", &types); + if (ret == Result::SUCCESS) { + int32_t len = types->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr arrayEle = types->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr pTypes = TypeObject::Create(*arrayEle); + if (pTypes == nullptr) { + error += "'types' format invalid;"; + } else { + typeProfileEntry->types_.emplace_back(std::move(pTypes)); + } + } + } else { + error += "Unknown 'types';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "TypeProfileEntry::Create " << error; + return nullptr; + } + + return typeProfileEntry; +} + +std::unique_ptr TypeProfileEntry::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("offset", offset_); + + std::unique_ptr types = PtJson::CreateArray(); + size_t len = types_.size(); + for (size_t i = 0; i < len; i++) { + types->Push(types_[i]->ToJson()); + } + result->Add("types", types); + + return result; +} + +std::unique_ptr ScriptTypeProfile::Create(const PtJson ¶ms) +{ + std::string error; + auto scriptTypeProfile = std::make_unique(); + Result ret; + + std::string scriptId; + ret = params.GetString("scriptId", &scriptId); + if (ret == Result::SUCCESS) { + scriptTypeProfile->scriptId_ = std::move(scriptId); + } else { + error += "Unknown 'scriptId';"; + } + + std::string url; + ret = params.GetString("url", &url); + if (ret == Result::SUCCESS) { + scriptTypeProfile->url_ = std::move(url); + } else { + error += "Unknown 'url';"; + } + + std::unique_ptr entries; + ret = params.GetArray("entries", &entries); + if (ret == Result::SUCCESS) { + int32_t len = entries->GetSize(); + for (int32_t i = 0; i < len; ++i) { + std::unique_ptr arrayEle = entries->Get(i); + ASSERT(arrayEle != nullptr); + std::unique_ptr pEntries = TypeProfileEntry::Create(*arrayEle); + if (pEntries == nullptr) { + error += "'entries' format invalid;"; + } else { + scriptTypeProfile->entries_.emplace_back(std::move(pEntries)); + } + } + } else { + error += "Unknown 'entries';"; + } + + if (!error.empty()) { + LOG(ERROR, DEBUGGER) << "ScriptTypeProfile::Create " << error; + return nullptr; + } + + return scriptTypeProfile; +} + +std::unique_ptr ScriptTypeProfile::ToJson() const +{ + std::unique_ptr result = PtJson::CreateObject(); + + result->Add("scriptId", scriptId_.c_str()); + result->Add("url", url_.c_str()); + + std::unique_ptr entries = PtJson::CreateArray(); + size_t len = entries_.size(); + for (size_t i = 0; i < len; i++) { + entries->Push(entries_[i]->ToJson()); + } + result->Add("entries", entries); + + return result; } +#endif } // namespace panda::ecmascript::tooling diff --git a/ecmascript/tooling/base/pt_types.h b/ecmascript/tooling/base/pt_types.h index 8165f1f21012374ec96d2101e2bac1bd007494b4..de59feb1310219b158f522a59e9b7a8dd2fdbd84 100644 --- a/ecmascript/tooling/base/pt_types.h +++ b/ecmascript/tooling/base/pt_types.h @@ -19,113 +19,107 @@ #include #include -#include "ecmascript/mem/c_containers.h" -#include "ecmascript/mem/c_string.h" -#include "ecmascript/tooling/interface/debugger_api.h" +#ifdef SUPPORT_PROFILER_CDP +#include "ecmascript/dfx/cpu_profiler/samples_record.h" +#endif +#include "ecmascript/tooling/backend/debugger_api.h" +#include "ecmascript/tooling/base/pt_json.h" #include "libpandabase/macros.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::CList; -using panda::ecmascript::CMap; -using panda::ecmascript::CQueue; -using panda::ecmascript::CString; -using panda::ecmascript::CVector; - // ========== Base types begin class PtBaseTypes { public: PtBaseTypes() = default; virtual ~PtBaseTypes() = default; - virtual Local ToObject(const EcmaVM *ecmaVm) = 0; - -protected: - static Local NewObject(const EcmaVM *ecmaVm); + virtual std::unique_ptr ToJson() const = 0; private: NO_COPY_SEMANTIC(PtBaseTypes); NO_MOVE_SEMANTIC(PtBaseTypes); friend class ProtocolHandler; - friend class JSBackend; + friend class DebuggerImpl; }; // ========== Debugger types begin // Debugger.BreakpointId -using BreakpointId = CString; +using BreakpointId = std::string; struct BreakpointDetails { static BreakpointId ToString(const BreakpointDetails &metaData) { - return "id:" + DebuggerApi::ToCString(metaData.line_) + ":" + DebuggerApi::ToCString(metaData.column_) + ":" + - metaData.url_; + return "id:" + std::to_string(metaData.line_) + ":" + std::to_string(metaData.column_) + ":" + + metaData.url_; } static bool ParseBreakpointId(const BreakpointId &id, BreakpointDetails *metaData) { auto lineStart = id.find(':'); - if (lineStart == CString::npos) { + if (lineStart == std::string::npos) { return false; } auto columnStart = id.find(':', lineStart + 1); - if (columnStart == CString::npos) { + if (columnStart == std::string::npos) { return false; } auto urlStart = id.find(':', columnStart + 1); - if (urlStart == CString::npos) { + if (urlStart == std::string::npos) { return false; } - CString lineStr = id.substr(lineStart + 1, columnStart - lineStart - 1); - CString columnStr = id.substr(columnStart + 1, urlStart - columnStart - 1); - CString url = id.substr(urlStart + 1); - metaData->line_ = DebuggerApi::CStringToULL(lineStr); - metaData->column_ = DebuggerApi::CStringToULL(columnStr); + std::string lineStr = id.substr(lineStart + 1, columnStart - lineStart - 1); + std::string columnStr = id.substr(columnStart + 1, urlStart - columnStart - 1); + std::string url = id.substr(urlStart + 1); + metaData->line_ = std::stoi(lineStr); + metaData->column_ = std::stoi(columnStr); metaData->url_ = url; return true; } - size_t line_ {0}; - size_t column_ {0}; - CString url_ {}; + int32_t line_ {0}; + int32_t column_ {0}; + std::string url_ {}; }; // Debugger.CallFrameId -using CallFrameId = CString; +using CallFrameId = int32_t; // ========== Runtime types begin // Runtime.ScriptId -using ScriptId = CString; +using ScriptId = int32_t; // Runtime.RemoteObjectId -using RemoteObjectId = CString; + +using RemoteObjectId = int32_t; // Runtime.ExecutionContextId using ExecutionContextId = int32_t; // Runtime.UnserializableValue -using UnserializableValue = CString; +using UnserializableValue = std::string; // Runtime.UniqueDebuggerId -using UniqueDebuggerId = CString; +using UniqueDebuggerId = int32_t; // Runtime.RemoteObject class RemoteObject : public PtBaseTypes { public: RemoteObject() = default; - virtual ~RemoteObject() override = default; + ~RemoteObject() override = default; - static std::unique_ptr FromTagged(const EcmaVM *ecmaVm, const Local &tagged); - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr FromTagged(const EcmaVM *ecmaVm, Local tagged); + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; /* * @see {#ObjectType} */ - CString GetType() const + const std::string &GetType() const { return type_; } - RemoteObject &SetType(const CString &type) + RemoteObject &SetType(const std::string &type) { type_ = type; return *this; @@ -133,28 +127,30 @@ public: /* * @see {#ObjectSubType} */ - CString GetSubType() const + const std::string &GetSubType() const { - return subtype_.value_or(""); + ASSERT(HasSubType()); + return subType_.value(); } - RemoteObject &SetSubType(const CString &type) + RemoteObject &SetSubType(const std::string &type) { - subtype_ = type; + subType_ = type; return *this; } bool HasSubType() const { - return subtype_.has_value(); + return subType_.has_value(); } - CString GetClassName() const + const std::string &GetClassName() const { - return className_.value_or(""); + ASSERT(HasClassName()); + return className_.value(); } - RemoteObject &SetClassName(const CString &className) + RemoteObject &SetClassName(const std::string &className) { className_ = className; return *this; @@ -170,7 +166,7 @@ public: return value_.value_or(Local()); } - RemoteObject &SetValue(const Local &value) + RemoteObject &SetValue(Local value) { value_ = value; return *this; @@ -181,9 +177,10 @@ public: return value_.has_value(); } - UnserializableValue GetUnserializableValue() const + const UnserializableValue &GetUnserializableValue() const { - return unserializableValue_.value_or(""); + ASSERT(HasUnserializableValue()); + return unserializableValue_.value(); } RemoteObject &SetUnserializableValue(const UnserializableValue &unserializableValue) @@ -197,12 +194,13 @@ public: return unserializableValue_.has_value(); } - CString GetDescription() const + const std::string &GetDescription() const { - return description_.value_or(""); + ASSERT(HasDescription()); + return description_.value(); } - RemoteObject &SetDescription(const CString &description) + RemoteObject &SetDescription(const std::string &description) { description_ = description; return *this; @@ -215,37 +213,31 @@ public: RemoteObjectId GetObjectId() const { - return objectId_.value_or(""); + return objectId_.value_or(0); } - RemoteObject &SetObjectId(const RemoteObjectId &objectId) + RemoteObject &SetObjectId(RemoteObjectId objectId) { objectId_ = objectId; return *this; } - RemoteObject &SetObjectId(uint32_t objectId) - { - objectId_ = DebuggerApi::ToCString(objectId); - return *this; - } - bool HasObjectId() const { return objectId_.has_value(); } struct TypeName { - static const CString Object; // NOLINT (readability-identifier-naming) - static const CString Function; // NOLINT (readability-identifier-naming) - static const CString Undefined; // NOLINT (readability-identifier-naming) - static const CString String; // NOLINT (readability-identifier-naming) - static const CString Number; // NOLINT (readability-identifier-naming) - static const CString Boolean; // NOLINT (readability-identifier-naming) - static const CString Symbol; // NOLINT (readability-identifier-naming) - static const CString Bigint; // NOLINT (readability-identifier-naming) - static const CString Wasm; // NOLINT (readability-identifier-naming) - static bool Valid(const CString &type) + static const std::string Object; // NOLINT (readability-identifier-naming) + static const std::string Function; // NOLINT (readability-identifier-naming) + static const std::string Undefined; // NOLINT (readability-identifier-naming) + static const std::string String; // NOLINT (readability-identifier-naming) + static const std::string Number; // NOLINT (readability-identifier-naming) + static const std::string Boolean; // NOLINT (readability-identifier-naming) + static const std::string Symbol; // NOLINT (readability-identifier-naming) + static const std::string Bigint; // NOLINT (readability-identifier-naming) + static const std::string Wasm; // NOLINT (readability-identifier-naming) + static bool Valid(const std::string &type) { return type == Object || type == Function || type == Undefined || type == String || type == Number || type == Boolean || type == Symbol || type == Bigint || type == Wasm; @@ -253,30 +245,30 @@ public: }; struct SubTypeName { - static const CString Array; // NOLINT (readability-identifier-naming) - static const CString Null; // NOLINT (readability-identifier-naming) - static const CString Node; // NOLINT (readability-identifier-naming) - static const CString Regexp; // NOLINT (readability-identifier-naming) - static const CString Date; // NOLINT (readability-identifier-naming) - static const CString Map; // NOLINT (readability-identifier-naming) - static const CString Set; // NOLINT (readability-identifier-naming) - static const CString Weakmap; // NOLINT (readability-identifier-naming) - static const CString Weakset; // NOLINT (readability-identifier-naming) - static const CString Iterator; // NOLINT (readability-identifier-naming) - static const CString Generator; // NOLINT (readability-identifier-naming) - static const CString Error; // NOLINT (readability-identifier-naming) - static const CString Proxy; // NOLINT (readability-identifier-naming) - static const CString Promise; // NOLINT (readability-identifier-naming) - static const CString Typedarray; // NOLINT (readability-identifier-naming) - static const CString Arraybuffer; // NOLINT (readability-identifier-naming) - static const CString Dataview; // NOLINT (readability-identifier-naming) - static const CString I32; // NOLINT (readability-identifier-naming) - static const CString I64; // NOLINT (readability-identifier-naming) - static const CString F32; // NOLINT (readability-identifier-naming) - static const CString F64; // NOLINT (readability-identifier-naming) - static const CString V128; // NOLINT (readability-identifier-naming) - static const CString Externref; // NOLINT (readability-identifier-naming) - static bool Valid(const CString &type) + static const std::string Array; // NOLINT (readability-identifier-naming) + static const std::string Null; // NOLINT (readability-identifier-naming) + static const std::string Node; // NOLINT (readability-identifier-naming) + static const std::string Regexp; // NOLINT (readability-identifier-naming) + static const std::string Date; // NOLINT (readability-identifier-naming) + static const std::string Map; // NOLINT (readability-identifier-naming) + static const std::string Set; // NOLINT (readability-identifier-naming) + static const std::string Weakmap; // NOLINT (readability-identifier-naming) + static const std::string Weakset; // NOLINT (readability-identifier-naming) + static const std::string Iterator; // NOLINT (readability-identifier-naming) + static const std::string Generator; // NOLINT (readability-identifier-naming) + static const std::string Error; // NOLINT (readability-identifier-naming) + static const std::string Proxy; // NOLINT (readability-identifier-naming) + static const std::string Promise; // NOLINT (readability-identifier-naming) + static const std::string Typedarray; // NOLINT (readability-identifier-naming) + static const std::string Arraybuffer; // NOLINT (readability-identifier-naming) + static const std::string Dataview; // NOLINT (readability-identifier-naming) + static const std::string I32; // NOLINT (readability-identifier-naming) + static const std::string I64; // NOLINT (readability-identifier-naming) + static const std::string F32; // NOLINT (readability-identifier-naming) + static const std::string F64; // NOLINT (readability-identifier-naming) + static const std::string V128; // NOLINT (readability-identifier-naming) + static const std::string Externref; // NOLINT (readability-identifier-naming) + static bool Valid(const std::string &type) { return type == Array || type == Null || type == Node || type == Regexp || type == Map || type == Set || type == Weakmap || type == Iterator || type == Generator || type == Error || type == Proxy || @@ -285,27 +277,27 @@ public: } }; struct ClassName { - static const CString Object; // NOLINT (readability-identifier-naming) - static const CString Function; // NOLINT (readability-identifier-naming) - static const CString Array; // NOLINT (readability-identifier-naming) - static const CString Regexp; // NOLINT (readability-identifier-naming) - static const CString Date; // NOLINT (readability-identifier-naming) - static const CString Map; // NOLINT (readability-identifier-naming) - static const CString Set; // NOLINT (readability-identifier-naming) - static const CString Weakmap; // NOLINT (readability-identifier-naming) - static const CString Weakset; // NOLINT (readability-identifier-naming) - static const CString ArrayIterator; // NOLINT (readability-identifier-naming) - static const CString StringIterator; // NOLINT (readability-identifier-naming) - static const CString SetIterator; // NOLINT (readability-identifier-naming) - static const CString MapIterator; // NOLINT (readability-identifier-naming) - static const CString Iterator; // NOLINT (readability-identifier-naming) - static const CString Error; // NOLINT (readability-identifier-naming) - static const CString Proxy; // NOLINT (readability-identifier-naming) - static const CString Promise; // NOLINT (readability-identifier-naming) - static const CString Typedarray; // NOLINT (readability-identifier-naming) - static const CString Arraybuffer; // NOLINT (readability-identifier-naming) - static const CString Global; // NOLINT (readability-identifier-naming) - static bool Valid(const CString &type) + static const std::string Object; // NOLINT (readability-identifier-naming) + static const std::string Function; // NOLINT (readability-identifier-naming) + static const std::string Array; // NOLINT (readability-identifier-naming) + static const std::string Regexp; // NOLINT (readability-identifier-naming) + static const std::string Date; // NOLINT (readability-identifier-naming) + static const std::string Map; // NOLINT (readability-identifier-naming) + static const std::string Set; // NOLINT (readability-identifier-naming) + static const std::string Weakmap; // NOLINT (readability-identifier-naming) + static const std::string Weakset; // NOLINT (readability-identifier-naming) + static const std::string ArrayIterator; // NOLINT (readability-identifier-naming) + static const std::string StringIterator; // NOLINT (readability-identifier-naming) + static const std::string SetIterator; // NOLINT (readability-identifier-naming) + static const std::string MapIterator; // NOLINT (readability-identifier-naming) + static const std::string Iterator; // NOLINT (readability-identifier-naming) + static const std::string Error; // NOLINT (readability-identifier-naming) + static const std::string Proxy; // NOLINT (readability-identifier-naming) + static const std::string Promise; // NOLINT (readability-identifier-naming) + static const std::string Typedarray; // NOLINT (readability-identifier-naming) + static const std::string Arraybuffer; // NOLINT (readability-identifier-naming) + static const std::string Global; // NOLINT (readability-identifier-naming) + static bool Valid(const std::string &type) { return type == Object || type == Array || type == Regexp || type == Date || type == Map || type == Set || type == Weakmap || type == Weakset || type == ArrayIterator || type == StringIterator || @@ -313,98 +305,76 @@ public: type == Promise || type == Typedarray || type == Arraybuffer || type == Function; } }; - static const CString ObjectDescription; // NOLINT (readability-identifier-naming) - static const CString GlobalDescription; // NOLINT (readability-identifier-naming) - static const CString ProxyDescription; // NOLINT (readability-identifier-naming) - static const CString PromiseDescription; // NOLINT (readability-identifier-naming) - static const CString ArrayIteratorDescription; // NOLINT (readability-identifier-naming) - static const CString StringIteratorDescription; // NOLINT (readability-identifier-naming) - static const CString SetIteratorDescription; // NOLINT (readability-identifier-naming) - static const CString MapIteratorDescription; // NOLINT (readability-identifier-naming) - static const CString WeakMapDescription; // NOLINT (readability-identifier-naming) - static const CString WeakSetDescription; // NOLINT (readability-identifier-naming) + static const std::string ObjectDescription; // NOLINT (readability-identifier-naming) + static const std::string GlobalDescription; // NOLINT (readability-identifier-naming) + static const std::string ProxyDescription; // NOLINT (readability-identifier-naming) + static const std::string PromiseDescription; // NOLINT (readability-identifier-naming) + static const std::string ArrayIteratorDescription; // NOLINT (readability-identifier-naming) + static const std::string StringIteratorDescription; // NOLINT (readability-identifier-naming) + static const std::string SetIteratorDescription; // NOLINT (readability-identifier-naming) + static const std::string MapIteratorDescription; // NOLINT (readability-identifier-naming) + static const std::string WeakMapDescription; // NOLINT (readability-identifier-naming) + static const std::string WeakSetDescription; // NOLINT (readability-identifier-naming) private: NO_COPY_SEMANTIC(RemoteObject); NO_MOVE_SEMANTIC(RemoteObject); - CString type_ {}; - std::optional subtype_ {}; - std::optional className_ {}; + std::string type_ {}; + std::optional subType_ {}; + std::optional className_ {}; std::optional> value_ {}; std::optional unserializableValue_ {}; - std::optional description_ {}; + std::optional description_ {}; std::optional objectId_ {}; }; class PrimitiveRemoteObject final : public RemoteObject { public: - explicit PrimitiveRemoteObject(const EcmaVM *ecmaVm, const Local &tagged); - virtual ~PrimitiveRemoteObject() override = default; + PrimitiveRemoteObject(const EcmaVM *ecmaVm, Local tagged); + ~PrimitiveRemoteObject() override = default; }; class StringRemoteObject final : public RemoteObject { public: - explicit StringRemoteObject(const EcmaVM *ecmaVm, const Local &tagged) - { - SetType(RemoteObject::TypeName::String).SetValue(tagged); - } + StringRemoteObject(const EcmaVM *ecmaVm, Local tagged); virtual ~StringRemoteObject() = default; }; class SymbolRemoteObject final : public RemoteObject { public: - explicit SymbolRemoteObject(const EcmaVM *ecmaVm, const Local &tagged) - { - SetType(RemoteObject::TypeName::Symbol).SetDescription(DescriptionForSymbol(ecmaVm, Local(tagged))); - } - virtual ~SymbolRemoteObject() override = default; + SymbolRemoteObject(const EcmaVM *ecmaVm, Local tagged); + ~SymbolRemoteObject() override = default; private: - CString DescriptionForSymbol(const EcmaVM *ecmaVm, const Local &tagged) const; + std::string DescriptionForSymbol(const EcmaVM *ecmaVm, Local tagged) const; }; class FunctionRemoteObject final : public RemoteObject { public: - FunctionRemoteObject(const EcmaVM *ecmaVm, const Local &tagged) - { - SetType(RemoteObject::TypeName::Function) - .SetClassName(RemoteObject::ClassName::Function) - .SetDescription(DescriptionForFunction(ecmaVm, tagged)); - } - virtual ~FunctionRemoteObject() override = default; + FunctionRemoteObject(const EcmaVM *ecmaVm, Local tagged); + ~FunctionRemoteObject() override = default; private: - CString DescriptionForFunction(const EcmaVM *ecmaVm, const Local &tagged) const; + std::string DescriptionForFunction(const EcmaVM *ecmaVm, Local tagged) const; }; class ObjectRemoteObject final : public RemoteObject { public: - explicit ObjectRemoteObject(const EcmaVM *ecmaVm, const Local &tagged, const CString &classname) - { - SetType(RemoteObject::TypeName::Object) - .SetClassName(classname) - .SetDescription(DescriptionForObject(ecmaVm, tagged)); - } - explicit ObjectRemoteObject(const EcmaVM *ecmaVm, const Local &tagged, const CString &classname, - const CString &subtype) - { - SetType(RemoteObject::TypeName::Object) - .SetSubType(subtype) - .SetClassName(classname) - .SetDescription(DescriptionForObject(ecmaVm, tagged)); - } - virtual ~ObjectRemoteObject() override = default; - static CString DescriptionForObject(const EcmaVM *ecmaVm, const Local &tagged); + ObjectRemoteObject(const EcmaVM *ecmaVm, Local tagged, const std::string &classname); + ObjectRemoteObject(const EcmaVM *ecmaVm, Local tagged, const std::string &classname, + const std::string &subtype); + ~ObjectRemoteObject() override = default; + static std::string DescriptionForObject(const EcmaVM *ecmaVm, Local tagged); private: - static CString DescriptionForArray(const EcmaVM *ecmaVm, const Local &tagged); - static CString DescriptionForRegexp(const EcmaVM *ecmaVm, const Local &tagged); - static CString DescriptionForDate(const EcmaVM *ecmaVm, const Local &tagged); - static CString DescriptionForMap(const Local &tagged); - static CString DescriptionForSet(const Local &tagged); - static CString DescriptionForError(const EcmaVM *ecmaVm, const Local &tagged); - static CString DescriptionForArrayBuffer(const EcmaVM *ecmaVm, const Local &tagged); + static std::string DescriptionForArray(const EcmaVM *ecmaVm, Local tagged); + static std::string DescriptionForRegexp(const EcmaVM *ecmaVm, Local tagged); + static std::string DescriptionForDate(const EcmaVM *ecmaVm, Local tagged); + static std::string DescriptionForMap(Local tagged); + static std::string DescriptionForSet(Local tagged); + static std::string DescriptionForError(const EcmaVM *ecmaVm, Local tagged); + static std::string DescriptionForArrayBuffer(const EcmaVM *ecmaVm, Local tagged); }; // Runtime.ExceptionDetails @@ -412,8 +382,8 @@ class ExceptionDetails final : public PtBaseTypes { public: ExceptionDetails() = default; ~ExceptionDetails() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; int32_t GetExceptionId() const { @@ -426,12 +396,12 @@ public: return *this; } - CString GetText() const + const std::string &GetText() const { return text_; } - ExceptionDetails &SetText(const CString &text) + ExceptionDetails &SetText(const std::string &text) { text_ = text; return *this; @@ -439,32 +409,32 @@ public: int32_t GetLine() const { - return line_; + return lineNumber_; } - ExceptionDetails &SetLine(size_t line) + ExceptionDetails &SetLine(int32_t lineNumber) { - line_ = line; + lineNumber_ = lineNumber; return *this; } int32_t GetColumn() const { - return column_; + return columnNumber_; } - ExceptionDetails &SetColumn(size_t column) + ExceptionDetails &SetColumn(int32_t columnNumber) { - column_ = column; + columnNumber_ = columnNumber; return *this; } ScriptId GetScriptId() const { - return scriptId_.value_or(""); + return scriptId_.value_or(0); } - ExceptionDetails &SetScriptId(const ScriptId &scriptId) + ExceptionDetails &SetScriptId(ScriptId scriptId) { scriptId_ = scriptId; return *this; @@ -475,12 +445,13 @@ public: return scriptId_.has_value(); } - CString GetUrl() const + const std::string &GetUrl() const { - return url_.value_or(""); + ASSERT(HasUrl()); + return url_.value(); } - ExceptionDetails &SetUrl(const CString &url) + ExceptionDetails &SetUrl(const std::string &url) { url_ = url; return *this; @@ -531,11 +502,11 @@ private: NO_MOVE_SEMANTIC(ExceptionDetails); int32_t exceptionId_ {0}; - CString text_ {}; - size_t line_ {0}; - size_t column_ {0}; + std::string text_ {}; + int32_t lineNumber_ {0}; + int32_t columnNumber_ {0}; std::optional scriptId_ {}; - std::optional url_ {}; + std::optional url_ {}; std::optional> exception_ {}; std::optional executionContextId_ {0}; }; @@ -546,15 +517,15 @@ public: InternalPropertyDescriptor() = default; ~InternalPropertyDescriptor() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; - CString GetName() const + std::string GetName() const { return name_; } - InternalPropertyDescriptor &SetName(const CString &name) + InternalPropertyDescriptor &SetName(const std::string &name) { name_ = name; return *this; @@ -583,7 +554,7 @@ private: NO_COPY_SEMANTIC(InternalPropertyDescriptor); NO_MOVE_SEMANTIC(InternalPropertyDescriptor); - CString name_ {}; + std::string name_ {}; std::optional> value_ {}; }; @@ -593,15 +564,15 @@ public: PrivatePropertyDescriptor() = default; ~PrivatePropertyDescriptor() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; - CString GetName() const + std::string GetName() const { return name_; } - PrivatePropertyDescriptor &SetName(const CString &name) + PrivatePropertyDescriptor &SetName(const std::string &name) { name_ = name; return *this; @@ -668,7 +639,7 @@ private: NO_COPY_SEMANTIC(PrivatePropertyDescriptor); NO_MOVE_SEMANTIC(PrivatePropertyDescriptor); - CString name_ {}; + std::string name_ {}; std::optional> value_ {}; std::optional> get_ {}; std::optional> set_ {}; @@ -680,17 +651,17 @@ public: PropertyDescriptor() = default; ~PropertyDescriptor() override = default; - static std::unique_ptr FromProperty(const EcmaVM *ecmaVm, const Local &name, + static std::unique_ptr FromProperty(const EcmaVM *ecmaVm, Local name, const PropertyAttribute &property); - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; - CString GetName() const + std::string GetName() const { return name_; } - PropertyDescriptor &SetName(const CString &name) + PropertyDescriptor &SetName(const std::string &name) { name_ = name; return *this; @@ -846,7 +817,7 @@ private: NO_COPY_SEMANTIC(PropertyDescriptor); NO_MOVE_SEMANTIC(PropertyDescriptor); - CString name_ {}; + std::string name_ {}; std::optional> value_ {}; std::optional writable_ {}; std::optional> get_ {}; @@ -864,15 +835,15 @@ public: CallArgument() = default; ~CallArgument() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; Local GetValue() const { return value_.value_or(Local()); } - CallArgument &SetValue(const Local &value) + CallArgument &SetValue(Local value) { value_ = value; return *this; @@ -883,9 +854,10 @@ public: return value_.has_value(); } - UnserializableValue GetUnserializableValue() const + const UnserializableValue &GetUnserializableValue() const { - return unserializableValue_.value_or(""); + ASSERT(HasUnserializableValue()); + return unserializableValue_.value(); } CallArgument &SetUnserializableValue(const UnserializableValue &unserializableValue) @@ -901,10 +873,10 @@ public: RemoteObjectId GetObjectId() const { - return objectId_.value_or(""); + return objectId_.value_or(0); } - CallArgument &SetObjectId(const RemoteObjectId &objectId) + CallArgument &SetObjectId(RemoteObjectId objectId) { objectId_ = objectId; return *this; @@ -927,15 +899,15 @@ private: // ========== Debugger types begin // Debugger.ScriptLanguage struct ScriptLanguage { - static bool Valid(const CString &language) + static bool Valid(const std::string &language) { return language == JavaScript() || language == WebAssembly(); } - static CString JavaScript() + static std::string JavaScript() { return "JavaScript"; } - static CString WebAssembly() + static std::string WebAssembly() { return "WebAssembly"; } @@ -945,17 +917,17 @@ struct ScriptLanguage { class Location : public PtBaseTypes { public: Location() = default; - virtual ~Location() override = default; + ~Location() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; ScriptId GetScriptId() const { return scriptId_; } - Location &SetScriptId(const ScriptId &scriptId) + Location &SetScriptId(ScriptId scriptId) { scriptId_ = scriptId; return *this; @@ -963,68 +935,68 @@ public: int32_t GetLine() const { - return line_; + return lineNumber_; } - Location &SetLine(size_t line) + Location &SetLine(int32_t line) { - line_ = line; + lineNumber_ = line; return *this; } int32_t GetColumn() const { - return column_.value_or(-1); + return columnNumber_.value_or(-1); } - Location &SetColumn(size_t column) + Location &SetColumn(int32_t column) { - column_ = column; + columnNumber_ = column; return *this; } bool HasColumn() const { - return column_.has_value(); + return columnNumber_.has_value(); } private: NO_COPY_SEMANTIC(Location); NO_MOVE_SEMANTIC(Location); - ScriptId scriptId_ {}; - size_t line_ {0}; - std::optional column_ {}; + ScriptId scriptId_ {0}; + int32_t lineNumber_ {0}; + std::optional columnNumber_ {}; }; // Debugger.ScriptPosition class ScriptPosition : public PtBaseTypes { public: ScriptPosition() = default; - virtual ~ScriptPosition() override = default; + ~ScriptPosition() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; int32_t GetLine() const { - return line_; + return lineNumber_; } - ScriptPosition &SetLine(size_t line) + ScriptPosition &SetLine(int32_t line) { - line_ = line; + lineNumber_ = line; return *this; } int32_t GetColumn() const { - return column_; + return columnNumber_; } - ScriptPosition &SetColumn(size_t column) + ScriptPosition &SetColumn(int32_t column) { - column_ = column; + columnNumber_ = column; return *this; } @@ -1032,41 +1004,41 @@ private: NO_COPY_SEMANTIC(ScriptPosition); NO_MOVE_SEMANTIC(ScriptPosition); - size_t line_ {0}; - size_t column_ {0}; + int32_t lineNumber_ {0}; + int32_t columnNumber_ {0}; }; // Debugger.SearchMatch class SearchMatch : public PtBaseTypes { public: SearchMatch() = default; - virtual ~SearchMatch() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + ~SearchMatch() override = default; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; private: NO_COPY_SEMANTIC(SearchMatch); NO_MOVE_SEMANTIC(SearchMatch); - size_t lineNumber_ {0}; - CString lineContent_ {}; + int32_t lineNumber_ {0}; + std::string lineContent_ {}; }; // Debugger.LocationRange class LocationRange : public PtBaseTypes { public: LocationRange() = default; - virtual ~LocationRange() override = default; + ~LocationRange() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; ScriptId GetScriptId() const { return scriptId_; } - LocationRange &SetScriptId(const ScriptId &scriptId) + LocationRange &SetScriptId(ScriptId scriptId) { scriptId_ = scriptId; return *this; @@ -1098,7 +1070,7 @@ private: NO_COPY_SEMANTIC(LocationRange); NO_MOVE_SEMANTIC(LocationRange); - ScriptId scriptId_ {}; + ScriptId scriptId_ {0}; std::unique_ptr start_ {nullptr}; std::unique_ptr end_ {nullptr}; }; @@ -1109,15 +1081,15 @@ public: BreakLocation() = default; ~BreakLocation() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; ScriptId GetScriptId() const { return scriptId_; } - BreakLocation &SetScriptId(const ScriptId &scriptId) + BreakLocation &SetScriptId(ScriptId scriptId) { scriptId_ = scriptId; return *this; @@ -1125,40 +1097,41 @@ public: int32_t GetLine() const { - return line_; + return lineNumber_; } - BreakLocation &SetLine(size_t line) + BreakLocation &SetLine(int32_t lineNumber) { - line_ = line; + lineNumber_ = lineNumber; return *this; } int32_t GetColumn() const { - return column_.value_or(-1); + return columnNumber_.value_or(-1); } - BreakLocation &SetColumn(size_t column) + BreakLocation &SetColumn(int32_t columnNumber) { - column_ = column; + columnNumber_ = columnNumber; return *this; } bool HasColumn() const { - return column_.has_value(); + return columnNumber_.has_value(); } /* * @see {#BreakType} */ - CString GetType() const + const std::string &GetType() const { - return type_.value_or(""); + ASSERT(HasType()); + return type_.value(); } - BreakLocation &SetType(const CString &type) + BreakLocation &SetType(const std::string &type) { type_ = type; return *this; @@ -1170,19 +1143,19 @@ public: } struct Type { - static bool Valid(const CString &type) + static bool Valid(const std::string &type) { return type == DebuggerStatement() || type == Call() || type == Return(); } - static CString DebuggerStatement() + static std::string DebuggerStatement() { return "debuggerStatement"; } - static CString Call() + static std::string Call() { return "call"; } - static CString Return() + static std::string Return() { return "return"; } @@ -1192,10 +1165,10 @@ private: NO_COPY_SEMANTIC(BreakLocation); NO_MOVE_SEMANTIC(BreakLocation); - ScriptId scriptId_ {}; - size_t line_ {0}; - std::optional column_ {}; - std::optional type_ {}; + ScriptId scriptId_ {0}; + int32_t lineNumber_ {0}; + std::optional columnNumber_ {}; + std::optional type_ {}; }; using BreakType = BreakLocation::Type; @@ -1218,18 +1191,18 @@ public: Scope() = default; ~Scope() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; /* * @see {#Scope::Type} */ - CString GetType() const + const std::string &GetType() const { return type_; } - Scope &SetType(const CString &type) + Scope &SetType(const std::string &type) { type_ = type; return *this; @@ -1246,12 +1219,13 @@ public: return *this; } - CString GetName() const + const std::string &GetName() const { - return name_.value_or(""); + ASSERT(HasName()); + return name_.value(); } - Scope &SetName(const CString &name) + Scope &SetName(const std::string &name) { name_ = name; return *this; @@ -1301,49 +1275,49 @@ public: } struct Type { - static bool Valid(const CString &type) + static bool Valid(const std::string &type) { return type == Global() || type == Local() || type == With() || type == Closure() || type == Catch() || type == Block() || type == Script() || type == Eval() || type == Module() || type == WasmExpressionStack(); } - static CString Global() + static std::string Global() { return "global"; } - static CString Local() + static std::string Local() { return "local"; } - static CString With() + static std::string With() { return "with"; } - static CString Closure() + static std::string Closure() { return "closure"; } - static CString Catch() + static std::string Catch() { return "catch"; } - static CString Block() + static std::string Block() { return "block"; } - static CString Script() + static std::string Script() { return "script"; } - static CString Eval() + static std::string Eval() { return "eval"; } - static CString Module() + static std::string Module() { return "module"; } - static CString WasmExpressionStack() + static std::string WasmExpressionStack() { return "wasm-expression-stack"; } @@ -1353,9 +1327,9 @@ private: NO_COPY_SEMANTIC(Scope); NO_MOVE_SEMANTIC(Scope); - CString type_ {}; + std::string type_ {}; std::unique_ptr object_ {nullptr}; - std::optional name_ {}; + std::optional name_ {}; std::optional> startLocation_ {}; std::optional> endLocation_ {}; }; @@ -1366,26 +1340,26 @@ public: CallFrame() = default; ~CallFrame() override = default; - static std::unique_ptr Create(const EcmaVM *ecmaVm, const Local ¶ms); - Local ToObject(const EcmaVM *ecmaVm) override; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; CallFrameId GetCallFrameId() const { return callFrameId_; } - CallFrame &SetCallFrameId(const CallFrameId &callFrameId) + CallFrame &SetCallFrameId(CallFrameId callFrameId) { callFrameId_ = callFrameId; return *this; } - CString GetFunctionName() const + const std::string &GetFunctionName() const { return functionName_; } - CallFrame &SetFunctionName(const CString &functionName) + CallFrame &SetFunctionName(const std::string &functionName) { functionName_ = functionName; return *this; @@ -1421,23 +1395,23 @@ public: return *this; } - CString GetUrl() const + const std::string &GetUrl() const { return url_; } - CallFrame &SetUrl(const CString &url) + CallFrame &SetUrl(const std::string &url) { url_ = url; return *this; } - const CVector> *GetScopeChain() const + const std::vector> *GetScopeChain() const { return &scopeChain_; } - CallFrame &SetScopeChain(CVector> scopeChain) + CallFrame &SetScopeChain(std::vector> scopeChain) { scopeChain_ = std::move(scopeChain); return *this; @@ -1477,13 +1451,757 @@ private: NO_MOVE_SEMANTIC(CallFrame); CallFrameId callFrameId_ {}; - CString functionName_ {}; + std::string functionName_ {}; std::optional> functionLocation_ {}; std::unique_ptr location_ {nullptr}; - CString url_ {}; - CVector> scopeChain_ {}; + std::string url_ {}; + std::vector> scopeChain_ {}; std::unique_ptr this_ {nullptr}; std::optional> returnValue_ {}; }; + +#ifdef SUPPORT_PROFILER_CDP +// ========== Heapprofiler types begin + +using HeapSnapshotObjectId = int32_t; + +class SamplingHeapProfileSample final : public PtBaseTypes { +public: + SamplingHeapProfileSample() = default; + ~SamplingHeapProfileSample() override = default; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + SamplingHeapProfileSample &SetSize(int32_t size) + { + size_ = size; + return *this; + } + + int32_t GetSize() const + { + return size_; + } + + SamplingHeapProfileSample &SetNodeId(int32_t nodeId) + { + nodeId_ = nodeId; + return *this; + } + + int32_t GetNodeId() const + { + return nodeId_; + } + + SamplingHeapProfileSample &SetOrdinal(int32_t ordinal) + { + ordinal_ = ordinal; + return *this; + } + + int32_t GetOrdinal() const + { + return ordinal_; + } + +private: + NO_COPY_SEMANTIC(SamplingHeapProfileSample); + NO_MOVE_SEMANTIC(SamplingHeapProfileSample); + + int32_t size_ {0}; + int32_t nodeId_ {0}; + int32_t ordinal_ {0}; +}; + +class RuntimeCallFrame final : public PtBaseTypes { +public: + RuntimeCallFrame() = default; + ~RuntimeCallFrame() override = default; + static std::unique_ptr Create(const PtJson ¶ms); + static std::unique_ptr FromFrameInfo(const FrameInfo &cpuFrameInfo); + std::unique_ptr ToJson() const override; + + RuntimeCallFrame &SetFunctionName(const std::string &functionName) + { + functionName_ = functionName; + return *this; + } + + const std::string &GetFunctionName() const + { + return functionName_; + } + + RuntimeCallFrame &SetScriptId(const std::string &scriptId) + { + scriptId_ = scriptId; + return *this; + } + + const std::string &GetScriptId() const + { + return scriptId_; + } + + RuntimeCallFrame &SetUrl(const std::string &url) + { + url_ = url; + return *this; + } + + const std::string &GetUrl() const + { + return url_; + } + + RuntimeCallFrame &SetLineNumber(int32_t lineNumber) + { + lineNumber_ = lineNumber; + return *this; + } + + int32_t GetLineNumber() const + { + return lineNumber_; + } + + RuntimeCallFrame &SetColumnNumber(int32_t columnNumber) + { + columnNumber_ = columnNumber; + return *this; + } + + int32_t GetColumnNumber() const + { + return columnNumber_; + } + +private: + NO_COPY_SEMANTIC(RuntimeCallFrame); + NO_MOVE_SEMANTIC(RuntimeCallFrame); + + std::string functionName_ {}; + std::string scriptId_ {}; + std::string url_ {}; + int32_t lineNumber_ {0}; + int32_t columnNumber_ {0}; +}; + +class SamplingHeapProfileNode final : public PtBaseTypes { +public: + SamplingHeapProfileNode() = default; + ~SamplingHeapProfileNode() override = default; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + SamplingHeapProfileNode &SetCallFrame(std::unique_ptr callFrame) + { + callFrame_ = std::move(callFrame); + return *this; + } + + RuntimeCallFrame *GetCallFrame() const + { + return callFrame_.get(); + } + + SamplingHeapProfileNode &SetSelfSize(int32_t selfSize) + { + selfSize_ = selfSize; + return *this; + } + + int32_t GetSelfSize() const + { + return selfSize_; + } + + SamplingHeapProfileNode &SetId(int32_t id) + { + id_ = id; + return *this; + } + + int32_t GetId() const + { + return id_; + } + + SamplingHeapProfileNode &SetChildren(std::vector> children) + { + children_ = std::move(children); + return *this; + } + + const std::vector> *GetChildren() const + { + return &children_; + } + +private: + NO_COPY_SEMANTIC(SamplingHeapProfileNode); + NO_MOVE_SEMANTIC(SamplingHeapProfileNode); + + std::unique_ptr callFrame_ {nullptr}; + int32_t selfSize_ {0}; + int32_t id_ {0}; + std::vector> children_ {}; +}; + +class SamplingHeapProfile final : public PtBaseTypes { +public: + SamplingHeapProfile() = default; + ~SamplingHeapProfile() override = default; + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + SamplingHeapProfile &SetHead(std::unique_ptr head) + { + head_ = std::move(head); + return *this; + } + + SamplingHeapProfileNode *GetHead() const + { + return head_.get(); + } + + SamplingHeapProfile &SetSamples(std::vector> samples) + { + samples_ = std::move(samples); + return *this; + } + + const std::vector> *GetSamples() const + { + return &samples_; + } + +private: + NO_COPY_SEMANTIC(SamplingHeapProfile); + NO_MOVE_SEMANTIC(SamplingHeapProfile); + + std::unique_ptr head_ {nullptr}; + std::vector> samples_ {}; +}; + +// ========== Profiler types begin +// Profiler.PositionTickInfo +class PositionTickInfo final : public PtBaseTypes { +public: + PositionTickInfo() = default; + ~PositionTickInfo() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + int32_t GetLine() const + { + return line_; + } + + PositionTickInfo &SetLine(int32_t line) + { + line_ = line; + return *this; + } + + int32_t GetTicks() const + { + return ticks_; + } + + PositionTickInfo &SetTicks(int32_t ticks) + { + ticks_ = ticks; + return *this; + } + +private: + NO_COPY_SEMANTIC(PositionTickInfo); + NO_MOVE_SEMANTIC(PositionTickInfo); + int32_t line_ {0}; + int32_t ticks_ {0}; +}; + +// Profiler.ProfileNode +class ProfileNode final : public PtBaseTypes { +public: + ProfileNode() = default; + ~ProfileNode() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + static std::unique_ptr FromCpuProfileNode(const CpuProfileNode &cpuProfileNode); + std::unique_ptr ToJson() const override; + + int32_t GetId() const + { + return id_; + } + + ProfileNode &SetId(int32_t id) + { + id_ = id; + return *this; + } + + RuntimeCallFrame *GetCallFrame() const + { + return callFrame_.get(); + } + + ProfileNode &SetCallFrame(std::unique_ptr callFrame) + { + callFrame_ = std::move(callFrame); + return *this; + } + + int32_t GetHitCount() const + { + ASSERT(HasHitCount()); + return hitCount_.value(); + } + + ProfileNode &SetHitCount(int32_t hitCount) + { + hitCount_ = hitCount; + return *this; + } + + bool HasHitCount() const + { + return hitCount_.has_value(); + } + + const std::vector *GetChildren() const + { + if (children_) { + return &children_.value(); + } + return nullptr; + } + + ProfileNode &SetChildren(std::vector children) + { + children_ = std::move(children); + return *this; + } + + bool HasChildren() const + { + return children_.has_value(); + } + + const std::vector> *GetPositionTicks() const + { + if (positionTicks_) { + return &positionTicks_.value(); + } + return nullptr; + } + + ProfileNode &SetPositionTicks(std::vector> positionTicks) + { + positionTicks_ = std::move(positionTicks); + return *this; + } + + bool HasPositionTicks() const + { + return positionTicks_.has_value(); + } + + const std::string &GetDeoptReason() const + { + ASSERT(HasDeoptReason()); + return deoptReason_.value(); + } + + ProfileNode &SetDeoptReason(const std::string &deoptReason) + { + deoptReason_ = deoptReason; + return *this; + } + + bool HasDeoptReason() const + { + return deoptReason_.has_value(); + } + +private: + NO_COPY_SEMANTIC(ProfileNode); + NO_MOVE_SEMANTIC(ProfileNode); + int32_t id_ {0}; + std::unique_ptr callFrame_ {nullptr}; + std::optional hitCount_ {0}; + std::optional> children_ {}; + std::optional>> positionTicks_ {}; + std::optional deoptReason_ {}; +}; + +// Profiler.Profile +class Profile final : public PtBaseTypes { +public: + Profile() = default; + ~Profile() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + static std::unique_ptr FromProfileInfo(const ProfileInfo &profileInfo); + std::unique_ptr ToJson() const override; + + int64_t GetStartTime() const + { + return startTime_; + } + + Profile &SetStartTime(int64_t startTime) + { + startTime_ = startTime; + return *this; + } + + int64_t GetEndTime() const + { + return endTime_; + } + + Profile &SetEndTime(int64_t endTime) + { + endTime_ = endTime; + return *this; + } + + const std::vector> *GetNodes() const + { + return &nodes_; + } + + Profile &SetNodes(std::vector> nodes) + { + nodes_ = std::move(nodes); + return *this; + } + + const std::vector *GetSamples() const + { + if (samples_) { + return &samples_.value(); + } + return nullptr; + } + + Profile &SetSamples(std::vector samples) + { + samples_ = std::move(samples); + return *this; + } + + bool HasSamples() const + { + return samples_.has_value(); + } + + const std::vector *GetTimeDeltas() const + { + if (timeDeltas_) { + return &timeDeltas_.value(); + } + return nullptr; + } + + Profile &SetTimeDeltas(std::vector timeDeltas) + { + timeDeltas_ = std::move(timeDeltas); + return *this; + } + + bool HasTimeDeltas() const + { + return timeDeltas_.has_value(); + } + +private: + NO_COPY_SEMANTIC(Profile); + NO_MOVE_SEMANTIC(Profile); + + int64_t startTime_ {0}; + int64_t endTime_ {0}; + std::vector> nodes_ {}; + std::optional> samples_ {}; + std::optional> timeDeltas_ {}; +}; + +// Profiler.Coverage +class Coverage final : public PtBaseTypes { +public: + Coverage() = default; + ~Coverage() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + int32_t GetStartOffset() const + { + return startOffset_; + } + + Coverage &SetStartOffset(int32_t startOffset) + { + startOffset_ = startOffset; + return *this; + } + + int32_t GetEndOffset() const + { + return endOffset_; + } + + Coverage &SetEndOffset(int32_t endOffset) + { + endOffset_ = endOffset; + return *this; + } + + int32_t GetCount() const + { + return count_; + } + + Coverage &SetCount(int32_t count) + { + count_ = count; + return *this; + } + +private: + NO_COPY_SEMANTIC(Coverage); + NO_MOVE_SEMANTIC(Coverage); + + int32_t startOffset_ {0}; + int32_t endOffset_ {0}; + int32_t count_ {0}; +}; + +// Profiler.FunctionCoverage +class FunctionCoverage final : public PtBaseTypes { +public: + FunctionCoverage() = default; + ~FunctionCoverage() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + const std::string &GetFunctionName() const + { + return functionName_; + } + + FunctionCoverage &SetFunctionName(const std::string &functionName) + { + functionName_ = functionName; + return *this; + } + + const std::vector> *GetRanges() const + { + return &ranges_; + } + + FunctionCoverage &SetFunctions(std::vector> ranges) + { + ranges_ = std::move(ranges); + return *this; + } + + bool GetIsBlockCoverage() const + { + return isBlockCoverage_; + } + + FunctionCoverage &SetisBlockCoverage(bool isBlockCoverage) + { + isBlockCoverage_ = isBlockCoverage; + return *this; + } + +private: + NO_COPY_SEMANTIC(FunctionCoverage); + NO_MOVE_SEMANTIC(FunctionCoverage); + + std::string functionName_ {}; + std::vector> ranges_ {}; + bool isBlockCoverage_ {}; +}; + +// Profiler.ScriptCoverage +// Profiler.GetBestEffortCoverage and Profiler.TakePreciseCoverage share this return value type +class ScriptCoverage final : public PtBaseTypes { +public: + ScriptCoverage() = default; + ~ScriptCoverage() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + const std::string &GetScriptId() const + { + return scriptId_; + } + + ScriptCoverage &SetScriptId(const std::string &scriptId) + { + scriptId_ = scriptId; + return *this; + } + + const std::string &GetUrl() const + { + return url_; + } + + ScriptCoverage &SetUrl(const std::string &url) + { + url_ = url; + return *this; + } + + const std::vector> *GetFunctions() const + { + return &functions_; + } + + ScriptCoverage &SetFunctions(std::vector> functions) + { + functions_ = std::move(functions); + return *this; + } + +private: + NO_COPY_SEMANTIC(ScriptCoverage); + NO_MOVE_SEMANTIC(ScriptCoverage); + + std::string scriptId_ {}; + std::string url_ {}; + std::vector> functions_ {}; +}; + +// Profiler.TypeObject +class TypeObject final : public PtBaseTypes { +public: + TypeObject() = default; + ~TypeObject() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + const std::string &GetName() const + { + return name_; + } + + TypeObject &SetName(const std::string &name) + { + name_ = name; + return *this; + } + +private: + NO_COPY_SEMANTIC(TypeObject); + NO_MOVE_SEMANTIC(TypeObject); + + std::string name_ {}; +}; + +// Profiler.TypeProfileEntry +class TypeProfileEntry final : public PtBaseTypes { +public: + TypeProfileEntry() = default; + ~TypeProfileEntry() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + int32_t GetOffset() const + { + return offset_; + } + + TypeProfileEntry &SetOffset(int32_t offset) + { + offset_ = offset; + return *this; + } + + const std::vector> *GetTypes() const + { + return &types_; + } + + TypeProfileEntry &SetTypes(std::vector> types) + { + types_ = std::move(types); + return *this; + } + +private: + NO_COPY_SEMANTIC(TypeProfileEntry); + NO_MOVE_SEMANTIC(TypeProfileEntry); + + int32_t offset_ {0}; + std::vector> types_ {}; +}; + +// Profiler.ScriptTypeProfile +class ScriptTypeProfile final : public PtBaseTypes { +public: + ScriptTypeProfile() = default; + ~ScriptTypeProfile() override = default; + + static std::unique_ptr Create(const PtJson ¶ms); + std::unique_ptr ToJson() const override; + + const std::string &GetScriptId() const + { + return scriptId_; + } + + ScriptTypeProfile &SetScriptId(const std::string &scriptId) + { + scriptId_ = scriptId; + return *this; + } + + const std::string &GetUrl() const + { + return url_; + } + + ScriptTypeProfile &SetUrl(const std::string &url) + { + url_ = url; + return *this; + } + + const std::vector> *GetEntries() const + { + return &entries_; + } + + ScriptTypeProfile &SetEntries(std::vector> entries) + { + entries_ = std::move(entries); + return *this; + } + +private: + NO_COPY_SEMANTIC(ScriptTypeProfile); + NO_MOVE_SEMANTIC(ScriptTypeProfile); + + std::string scriptId_ {}; + std::string url_ {}; + std::vector> entries_ {}; +}; +#endif } // namespace panda::ecmascript::tooling #endif diff --git a/ecmascript/tooling/debugger_service.cpp b/ecmascript/tooling/debugger_service.cpp index 12992c7a1a5d491fcc6136984ab4d2e9179c5745..1e91a31d301abaf190e3a4a1a0ca0c3dd3a0031c 100644 --- a/ecmascript/tooling/debugger_service.cpp +++ b/ecmascript/tooling/debugger_service.cpp @@ -14,16 +14,17 @@ */ #include "ecmascript/tooling/debugger_service.h" - #include "ecmascript/ecma_vm.h" #include "ecmascript/tooling/protocol_handler.h" +#include "ecmascript/tooling/interface/js_debugger_manager.h" namespace panda::ecmascript::tooling { void InitializeDebugger(const std::function &onResponse, ::panda::ecmascript::EcmaVM *vm) { ProtocolHandler *handler = vm->GetJsDebuggerManager()->GetDebuggerHandler(); if (handler != nullptr) { - LOG(FATAL, DEBUGGER) << "JS debugger was initialized"; + LOG(ERROR, DEBUGGER) << "JS debugger was initialized"; + return; } vm->GetJsDebuggerManager()->SetDebuggerHandler(new ProtocolHandler(onResponse, vm)); } @@ -39,7 +40,7 @@ void DispatchProtocolMessage(const ::panda::ecmascript::EcmaVM *vm, const std::s { ProtocolHandler *handler = vm->GetJsDebuggerManager()->GetDebuggerHandler(); if (handler != nullptr) { - handler->ProcessCommand(message.c_str()); + handler->ProcessCommand(message); } } } // namespace panda::ecmascript::tooling \ No newline at end of file diff --git a/ecmascript/tooling/debugger_service.h b/ecmascript/tooling/debugger_service.h index 16956934e2ac5251c444b7fe1e80bf562fe232ae..598614fb0b5b9f26d536d7c4c6a484a3df4dd5f1 100644 --- a/ecmascript/tooling/debugger_service.h +++ b/ecmascript/tooling/debugger_service.h @@ -23,7 +23,7 @@ namespace panda::ecmascript { class EcmaVM; -} // panda::ecmascript +} // namespace panda::ecmascript namespace panda::ecmascript::tooling { #ifdef __cplusplus diff --git a/ecmascript/tooling/dispatcher.cpp b/ecmascript/tooling/dispatcher.cpp index 7b7d1c7f5496e100f30614cb9cf58e76d307d260..72fd9d7123592be5662c8fbd4cacbf84d8fbd1d5 100644 --- a/ecmascript/tooling/dispatcher.cpp +++ b/ecmascript/tooling/dispatcher.cpp @@ -19,56 +19,42 @@ #include "ecmascript/tooling/agent/debugger_impl.h" #include "ecmascript/tooling/agent/runtime_impl.h" -#include "ecmascript/tooling/front_end.h" +#ifdef SUPPORT_PROFILER_CDP +#include "ecmascript/tooling/agent/heapprofiler_impl.h" +#include "ecmascript/tooling/agent/profiler_impl.h" +#endif +#include "ecmascript/tooling/protocol_channel.h" namespace panda::ecmascript::tooling { -DispatchRequest::DispatchRequest(const EcmaVM *ecmaVm, const CString &message) : ecmaVm_(ecmaVm) +DispatchRequest::DispatchRequest(const std::string &message) { - Local msgValue = JSON::Parse(ecmaVm, StringRef::NewFromUtf8(ecmaVm, message.c_str())); - if (msgValue->IsException()) { - DebuggerApi::ClearException(ecmaVm); - LOG(ERROR, DEBUGGER) << "json parse throw exception"; - return; - } - if (!msgValue->IsObject()) { + std::unique_ptr json = PtJson::Parse(message); + if (json == nullptr || !json->IsObject()) { code_ = RequestCode::JSON_PARSE_ERROR; LOG(ERROR, DEBUGGER) << "json parse error"; return; } - ObjectRef *msgObj = ObjectRef::Cast(*msgValue); - Local idStr = StringRef::NewFromUtf8(ecmaVm, "id"); - Local idResult = msgObj->Get(ecmaVm, idStr); - if (idResult.IsEmpty()) { + Result ret; + int32_t callId; + ret = json->GetInt("id", &callId); + if (ret != Result::SUCCESS) { code_ = RequestCode::PARSE_ID_ERROR; LOG(ERROR, DEBUGGER) << "parse id error"; return; } - if (!idResult->IsNumber()) { - code_ = RequestCode::ID_FORMAT_ERROR; - LOG(ERROR, DEBUGGER) << "id format error"; - return; - } - callId_ = static_cast(Local(idResult)->Value()); + callId_ = callId; - Local methodStr = StringRef::NewFromUtf8(ecmaVm, "method"); - Local methodResult = msgObj->Get(ecmaVm, methodStr); - if (methodResult.IsEmpty()) { + std::string wholeMethod; + ret = json->GetString("method", &wholeMethod); + if (ret != Result::SUCCESS) { code_ = RequestCode::PARSE_METHOD_ERROR; LOG(ERROR, DEBUGGER) << "parse method error"; return; } - if (!methodResult->IsString()) { - code_ = RequestCode::METHOD_FORMAT_ERROR; - LOG(ERROR, DEBUGGER) << "method format error"; - return; - } - CString wholeMethod = - DebuggerApi::ConvertToString(StringRef::Cast(*methodResult)->ToString()); - CString::size_type length = wholeMethod.length(); - CString::size_type indexPoint; - indexPoint = wholeMethod.find_first_of('.', 0); - if (indexPoint == CString::npos || indexPoint == 0 || indexPoint == length - 1) { + std::string::size_type length = wholeMethod.length(); + std::string::size_type indexPoint = wholeMethod.find_first_of('.', 0); + if (indexPoint == std::string::npos || indexPoint == 0 || indexPoint == length - 1) { code_ = RequestCode::METHOD_FORMAT_ERROR; LOG(ERROR, DEBUGGER) << "method format error: " << wholeMethod; return; @@ -80,20 +66,25 @@ DispatchRequest::DispatchRequest(const EcmaVM *ecmaVm, const CString &message) : LOG(DEBUG, DEBUGGER) << "domain: " << domain_; LOG(DEBUG, DEBUGGER) << "method: " << method_; - Local paramsStr = StringRef::NewFromUtf8(ecmaVm, "params"); - Local paramsValue = msgObj->Get(ecmaVm, paramsStr); - if (paramsValue.IsEmpty()) { + std::unique_ptr params; + ret = json->GetObject("params", ¶ms); + if (ret == Result::NOT_EXIST) { return; } - if (!paramsValue->IsObject()) { + if (ret == Result::TYPE_ERROR) { code_ = RequestCode::PARAMS_FORMAT_ERROR; LOG(ERROR, DEBUGGER) << "params format error"; return; } - params_ = paramsValue; + params_ = std::move(params); } -DispatchResponse DispatchResponse::Create(ResponseCode code, const CString &msg) +DispatchRequest::~DispatchRequest() +{ + params_->ReleaseRoot(); +} + +DispatchResponse DispatchResponse::Create(ResponseCode code, const std::string &msg) { DispatchResponse response; response.code_ = code; @@ -101,7 +92,7 @@ DispatchResponse DispatchResponse::Create(ResponseCode code, const CString &msg) return response; } -DispatchResponse DispatchResponse::Create(std::optional error) +DispatchResponse DispatchResponse::Create(std::optional error) { DispatchResponse response; if (error.has_value()) { @@ -116,7 +107,7 @@ DispatchResponse DispatchResponse::Ok() return DispatchResponse(); } -DispatchResponse DispatchResponse::Fail(const CString &message) +DispatchResponse DispatchResponse::Fail(const std::string &message) { DispatchResponse response; response.code_ = ResponseCode::NOK; @@ -125,20 +116,32 @@ DispatchResponse DispatchResponse::Fail(const CString &message) } void DispatcherBase::SendResponse(const DispatchRequest &request, const DispatchResponse &response, - std::unique_ptr result) + const PtBaseReturns &result) { - if (frontend_ != nullptr) { - frontend_->SendResponse(request, response, std::move(result)); + if (channel_ != nullptr) { + channel_->SendResponse(request, response, result); } } -Dispatcher::Dispatcher(FrontEnd *front) +Dispatcher::Dispatcher(const EcmaVM *vm, ProtocolChannel *channel) { - std::unique_ptr backend = std::make_unique(front); +#ifdef SUPPORT_PROFILER_CDP + // profiler + auto profiler = std::make_unique(vm, channel); + auto heapProfiler = std::make_unique(vm, channel); + dispatchers_["Profiler"] = + std::make_unique(channel, std::move(profiler)); + dispatchers_["HeapProfiler"] = + std::make_unique(channel, std::move(heapProfiler)); +#endif + + // debugger + auto runtime = std::make_unique(vm, channel); + auto debugger = std::make_unique(vm, channel, runtime.get()); dispatchers_["Runtime"] = - std::make_unique(front, std::make_unique(backend.get())); + std::make_unique(channel, std::move(runtime)); dispatchers_["Debugger"] = - std::make_unique(front, std::make_unique(std::move(backend))); + std::make_unique(channel, std::move(debugger)); } void Dispatcher::Dispatch(const DispatchRequest &request) @@ -147,7 +150,7 @@ void Dispatcher::Dispatch(const DispatchRequest &request) LOG(ERROR, DEBUGGER) << "Unknown request"; return; } - CString domain = request.GetDomain(); + const std::string &domain = request.GetDomain(); auto dispatcher = dispatchers_.find(domain); if (dispatcher != dispatchers_.end()) { dispatcher->second->Dispatch(request); diff --git a/ecmascript/tooling/dispatcher.h b/ecmascript/tooling/dispatcher.h index 3197ba2335cb507795c55e25517f5230c1110fcf..b247ba8bf6ed47147f8fc0f19243413690e6740c 100644 --- a/ecmascript/tooling/dispatcher.h +++ b/ecmascript/tooling/dispatcher.h @@ -19,16 +19,13 @@ #include #include -#include "libpandabase/macros.h" #include "ecmascript/napi/include/jsnapi.h" -#include "ecmascript/mem/c_containers.h" -#include "ecmascript/mem/c_string.h" -#include "include/tooling/debug_interface.h" +#include "ecmascript/tooling/backend/js_debugger_interface.h" +#include "ecmascript/tooling/base/pt_returns.h" +#include "libpandabase/macros.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::CMap; -using panda::ecmascript::CString; -class FrontEnd; +class ProtocolChannel; class PtBaseReturns; class PtBaseEvents; @@ -50,7 +47,8 @@ enum class ResponseCode : uint8_t { OK, NOK }; class DispatchRequest { public: - explicit DispatchRequest(const EcmaVM *ecmaVm, const CString &message); + explicit DispatchRequest(const std::string &message); + ~DispatchRequest(); bool IsValid() const { @@ -60,33 +58,26 @@ public: { return callId_; } - Local GetParams() const + const PtJson &GetParams() const { - return params_; + return *params_; } - CString GetDomain() const + const std::string &GetDomain() const { return domain_; } - CString GetMethod() const + const std::string &GetMethod() const { return method_; } - const EcmaVM *GetEcmaVM() const - { - return ecmaVm_; - } - - ~DispatchRequest() = default; private: - const EcmaVM *ecmaVm_ {nullptr}; - int32_t callId_ {-1}; - CString domain_ {}; - CString method_ {}; - Local params_ {}; + int32_t callId_ = -1; + std::string domain_ {}; + std::string method_ {}; + std::unique_ptr params_ = std::make_unique(); RequestCode code_ {RequestCode::OK}; - CString errorMsg_ {}; + std::string errorMsg_ {}; }; class DispatchResponse { @@ -101,15 +92,15 @@ public: return code_; } - CString GetMessage() const + const std::string &GetMessage() const { return errorMsg_; } - static DispatchResponse Create(ResponseCode code, const CString &msg = ""); - static DispatchResponse Create(std::optional error); + static DispatchResponse Create(ResponseCode code, const std::string &msg = ""); + static DispatchResponse Create(std::optional error); static DispatchResponse Ok(); - static DispatchResponse Fail(const CString &message); + static DispatchResponse Fail(const std::string &message); ~DispatchResponse() = default; @@ -117,24 +108,24 @@ private: DispatchResponse() = default; ResponseCode code_ {ResponseCode::OK}; - CString errorMsg_ {}; + std::string errorMsg_ {}; }; class DispatcherBase { public: - explicit DispatcherBase(FrontEnd *frontend) : frontend_(frontend) {} + explicit DispatcherBase(ProtocolChannel *channel) : channel_(channel) {} virtual ~DispatcherBase() { - frontend_ = nullptr; + channel_ = nullptr; }; virtual void Dispatch(const DispatchRequest &request) = 0; protected: void SendResponse(const DispatchRequest &request, const DispatchResponse &response, - std::unique_ptr result); + const PtBaseReturns &result = PtBaseReturns()); private: - FrontEnd *frontend_ {nullptr}; + ProtocolChannel *channel_ {nullptr}; NO_COPY_SEMANTIC(DispatcherBase); NO_MOVE_SEMANTIC(DispatcherBase); @@ -142,12 +133,12 @@ private: class Dispatcher { public: - explicit Dispatcher(FrontEnd *front); + explicit Dispatcher(const EcmaVM *vm, ProtocolChannel *channel); ~Dispatcher() = default; void Dispatch(const DispatchRequest &request); private: - CMap> dispatchers_ {}; + std::unordered_map> dispatchers_ {}; NO_COPY_SEMANTIC(Dispatcher); NO_MOVE_SEMANTIC(Dispatcher); diff --git a/ecmascript/tooling/interface/file_stream.cpp b/ecmascript/tooling/interface/file_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48bc240fc32349af3b03e84cf890b5c4a517e2cf --- /dev/null +++ b/ecmascript/tooling/interface/file_stream.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/tooling/interface/file_stream.h" + +#include +#include + +#include "ecmascript/ecma_macros.h" +#include "libpandabase/utils/logger.h" + +namespace panda::ecmascript { +FileStream::FileStream(const std::string &fileName) +{ + Initialize(fileName); +} + +void FileStream::EndOfStream() +{ + if (Good()) { + fileStream_.close(); + } +} + +bool FileStream::Good() +{ + return fileStream_.good(); +} + +void FileStream::Initialize(const std::string &fileName) +{ + // check file name + std::pair realPath = FilePathValid(fileName); + if (!realPath.first) { + LOG_ECMA(ERROR) << "FileStream: check file path failed"; + fileStream_.close(); + return; + } + + fileStream_.open(realPath.second.c_str(), std::ios::out); + if (fileStream_.fail()) { + LOG_ECMA(ERROR) << "FileStream: open file failed"; + } +} + +std::pair FileStream::FilePathValid(const std::string &fileName) +{ + if (fileName.empty() || fileName.size() > PATH_MAX) { + return std::make_pair(false, ""); + } + char resolvedPath[PATH_MAX] = {0}; + auto result = realpath(fileName.c_str(), resolvedPath); + if (result == resolvedPath || errno == ENOENT) { + return std::make_pair(true, std::string(resolvedPath)); + } + return std::make_pair(false, ""); +} + +// Writes the chunk of data into the stream +bool FileStream::WriteChunk(char *data, int32_t size) +{ + if (fileStream_.fail()) { + return false; + } + + std::string str; + str.resize(size); + for (int32_t i = 0; i < size; ++i) { + str[i] = data[i]; + } + + fileStream_ << str; + + return true; +} + +void FileDescriptorStream::EndOfStream() +{ + if (Good()) { + close(fd_); + } +} + +bool FileDescriptorStream::Good() +{ + return fd_ > 0; +} + +// Writes the chunk of data into the stream +bool FileDescriptorStream::WriteChunk(char *data, int32_t size) +{ + if (fd_ < 0) { + return false; + } + + std::string str; + str.resize(size); + for (int32_t i = 0; i < size; ++i) { + str[i] = data[i]; + } + int ret = dprintf(fd_, "%s", str.c_str()); + if (ret < 0) { + LOG_ECMA(ERROR) << "Write FD print failed, ret" << ret; + return false; + } + ret = fsync(fd_); + if (ret < 0) { + LOG_ECMA(ERROR) << "Write FD file failed, ret" << ret; + return false; + } + return true; +} +} \ No newline at end of file diff --git a/ecmascript/tooling/interface/file_stream.h b/ecmascript/tooling/interface/file_stream.h new file mode 100644 index 0000000000000000000000000000000000000000..eba3c3e8e23ef9662e519f38074dda1af83e4c2f --- /dev/null +++ b/ecmascript/tooling/interface/file_stream.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_TOOLING_INTERFACE_FILE_STREAM_H +#define ECMASCRIPT_TOOLING_INTERFACE_FILE_STREAM_H + +#include + +#include "ecmascript/tooling/interface/stream.h" + +namespace panda::ecmascript { +class FileStream : public Stream { +public: + FileStream(const std::string &fileName); + ~FileStream() override = default; + + void EndOfStream() override; + + // Get chunk's size + int GetSize() override + { + const static int fileChunkSize = 10240; + return fileChunkSize; + } + + // Writes the chunk of data into the stream + bool WriteChunk(char* data, int32_t size) override; + bool Good() override; + void UpdateHeapStats([[maybe_unused]] HeapStat* data, [[maybe_unused]] int32_t count) override + { + } + void UpdateLastSeenObjectId([[maybe_unused]] int32_t lastSeenObjectId) override + { + } + +private: + void Initialize(const std::string &fileName); + std::pair FilePathValid(const std::string &fileName); + + std::fstream fileStream_; +}; + +class FileDescriptorStream : public Stream { +public: + explicit FileDescriptorStream(int32_t fd): fd_(fd) {} + ~FileDescriptorStream() override = default; + + void EndOfStream() override; + + // Get chunk's size + int GetSize() override + { + const static int fileChunkSize = 10240; + return fileChunkSize; + } + + // Writes the chunk of data into the stream + bool WriteChunk(char *data, int32_t size) override; + bool Good() override; + void UpdateHeapStats([[maybe_unused]] HeapStat* data, [[maybe_unused]] int32_t count) override + { + } + void UpdateLastSeenObjectId([[maybe_unused]] int32_t lastSeenObjectId) override + { + } + +private: + int32_t fd_; +}; +} // namespace panda::ecmascript::tooling + +#endif // ECMASCRIPT_TOOLING_INTERFACE_FILE_STREAM_H diff --git a/ecmascript/tooling/interface/js_debugger_manager.h b/ecmascript/tooling/interface/js_debugger_manager.h index 3fc69741fcc7db77f82bce65ced4f860b518c308..0aad80d9d932e2f1b9a17f473dec52955867b915 100644 --- a/ecmascript/tooling/interface/js_debugger_manager.h +++ b/ecmascript/tooling/interface/js_debugger_manager.h @@ -28,7 +28,7 @@ class JsDebuggerManager { public: using LibraryHandle = os::library_loader::LibraryHandle; using ObjectUpdaterFunc = - std::function &)>; + std::function)>; JsDebuggerManager() = default; ~JsDebuggerManager() @@ -94,7 +94,7 @@ public: updaterFunc_ = updaterFunc; } - void NotifyLocalScopeUpdated(const CString &varName, const Local &value) + void NotifyLocalScopeUpdated(std::string_view varName, Local value) { if (updaterFunc_ != nullptr) { (*updaterFunc_)(frameHandler_.get(), varName, value); diff --git a/ecmascript/tooling/interface/notification_manager.h b/ecmascript/tooling/interface/notification_manager.h index 1af83585c7139d6615fee88baf8aa2adbd64eba0..a7a4efd4a3f5fc5db3e5a8a3557d45d9c94a80f4 100644 --- a/ecmascript/tooling/interface/notification_manager.h +++ b/ecmascript/tooling/interface/notification_manager.h @@ -21,9 +21,6 @@ #include "ecmascript/js_thread.h" namespace panda::ecmascript::tooling { -using panda::ecmascript::JSThread; -using panda::ecmascript::JSMethod; - class RuntimeListener { public: RuntimeListener() = default; @@ -38,6 +35,7 @@ public: virtual void VmStart() = 0; virtual void VmDeath() = 0; + virtual void PendingJobEntry() = 0; }; class NotificationManager { @@ -70,6 +68,13 @@ public: } } + void PendingJobEntryEvent() const + { + if (UNLIKELY(listener_ != nullptr)) { + listener_->PendingJobEntry(); + } + } + void VmStartEvent() const { if (UNLIKELY(listener_ != nullptr)) { diff --git a/ecmascript/tooling/interface/progress.h b/ecmascript/tooling/interface/progress.h new file mode 100644 index 0000000000000000000000000000000000000000..8ef98ebbb733661ce0327c18fcdf0ba741ff0a83 --- /dev/null +++ b/ecmascript/tooling/interface/progress.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_TOOLING_INTERFACE_PROGRESS_H +#define ECMASCRIPT_TOOLING_INTERFACE_PROGRESS_H + +#include + +namespace panda::ecmascript { +class Progress { +public: + virtual ~Progress() = default; + + virtual void ReportProgress(int32_t done, int32_t total) = 0; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_TOOLING_INTERFACE_PROGRESS_H diff --git a/ecmascript/tooling/interface/stream.h b/ecmascript/tooling/interface/stream.h new file mode 100644 index 0000000000000000000000000000000000000000..cd7285b65d31f1ab93e041b5aee9a7de66883bf2 --- /dev/null +++ b/ecmascript/tooling/interface/stream.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_TOOLING_INTERFACE_STREAM_H +#define ECMASCRIPT_TOOLING_INTERFACE_STREAM_H + +namespace panda::ecmascript { +class HeapStat { +public: + HeapStat(int32_t index, int32_t count, int32_t size) + : index_(index), count_(count), size_(size) {} + + int32_t index_; + int32_t count_; + int32_t size_; +}; + +class Stream { +public: + virtual ~Stream() = default; + + virtual void EndOfStream() = 0; + + // Get chunk's size + virtual int GetSize() = 0; + + // Writes the chunk of data into the stream + virtual bool WriteChunk(char *data, int32_t size) = 0; + virtual bool Good() = 0; + virtual void UpdateHeapStats(HeapStat* data, int32_t count) = 0; + virtual void UpdateLastSeenObjectId(int32_t lastSeenObjectId) = 0; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_TOOLING_INTERFACE_STREAM_H diff --git a/ecmascript/tooling/front_end.h b/ecmascript/tooling/protocol_channel.h similarity index 70% rename from ecmascript/tooling/front_end.h rename to ecmascript/tooling/protocol_channel.h index 826af75baa1d2de6f29e230ff00a59ecea4b8da0..3c2d7ba23874fc7bbc2f1f4595a138c4fb8a6a12 100644 --- a/ecmascript/tooling/front_end.h +++ b/ecmascript/tooling/protocol_channel.h @@ -13,30 +13,31 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_TOOLING_FRONT_END_H -#define ECMASCRIPT_TOOLING_FRONT_END_H +#ifndef ECMASCRIPT_TOOLING_PROTOCOL_CHANNEL_H +#define ECMASCRIPT_TOOLING_PROTOCOL_CHANNEL_H -#include "libpandabase/macros.h" #include "ecmascript/tooling/base/pt_events.h" #include "ecmascript/tooling/base/pt_returns.h" #include "ecmascript/tooling/dispatcher.h" +#include "libpandabase/macros.h" + namespace panda::ecmascript::tooling { -class FrontEnd { +class ProtocolChannel { public: - FrontEnd() = default; - virtual ~FrontEnd() = default; + ProtocolChannel() = default; + virtual ~ProtocolChannel() = default; virtual void WaitForDebugger() = 0; virtual void RunIfWaitingForDebugger() = 0; virtual void SendResponse(const DispatchRequest &request, const DispatchResponse &response, - std::unique_ptr result) = 0; - virtual void SendNotification(const EcmaVM *ecmaVm, std::unique_ptr events) = 0; + const PtBaseReturns &result) = 0; + virtual void SendNotification(const PtBaseEvents &events) = 0; private: - NO_COPY_SEMANTIC(FrontEnd); - NO_MOVE_SEMANTIC(FrontEnd); + NO_COPY_SEMANTIC(ProtocolChannel); + NO_MOVE_SEMANTIC(ProtocolChannel); }; } // namespace panda::ecmascript::tooling -#endif \ No newline at end of file +#endif // ECMASCRIPT_TOOLING_PROTOCOL_CHANNEL_H \ No newline at end of file diff --git a/ecmascript/tooling/protocol_handler.cpp b/ecmascript/tooling/protocol_handler.cpp index f64a399b08d21e648dac7641cb6e93375d95a933..be0597a3804fc8711f4b302c634bb1d57d2485e9 100644 --- a/ecmascript/tooling/protocol_handler.cpp +++ b/ecmascript/tooling/protocol_handler.cpp @@ -15,17 +15,10 @@ #include "ecmascript/tooling/protocol_handler.h" -#include "ecmascript/base/string_helper.h" #include "ecmascript/tooling/agent/debugger_impl.h" #include "utils/logger.h" namespace panda::ecmascript::tooling { -ProtocolHandler::ProtocolHandler(std::function callback, const EcmaVM *vm) - : callback_(std::move(callback)), vm_(vm) -{ - dispatcher_ = std::make_unique(this); -} - void ProtocolHandler::WaitForDebugger() { waitingForDebugger_ = true; @@ -40,77 +33,57 @@ void ProtocolHandler::RunIfWaitingForDebugger() waitingForDebugger_ = false; } -void ProtocolHandler::ProcessCommand(const CString &msg) +void ProtocolHandler::ProcessCommand(const std::string &msg) { LOG(DEBUG, DEBUGGER) << "ProtocolHandler::ProcessCommand: " << msg; [[maybe_unused]] LocalScope scope(vm_); Local exception = DebuggerApi::GetAndClearException(vm_); - dispatcher_->Dispatch(DispatchRequest(vm_, msg)); - DebuggerApi::ClearException(vm_); - if (!exception->IsHole()) { - DebuggerApi::SetException(vm_, exception); - } - CString startDebugging("Runtime.runIfWaitingForDebugger"); - if (msg.find(startDebugging, 0) != CString::npos) { - waitingForDebugger_ = false; - } + dispatcher_.Dispatch(DispatchRequest(msg)); + DebuggerApi::SetException(vm_, exception); } void ProtocolHandler::SendResponse(const DispatchRequest &request, const DispatchResponse &response, - std::unique_ptr result) + const PtBaseReturns &result) { LOG(INFO, DEBUGGER) << "ProtocolHandler::SendResponse: " << (response.IsOk() ? "success" : "failed: " + response.GetMessage()); - const EcmaVM *ecmaVm = request.GetEcmaVM(); - Local reply = PtBaseTypes::NewObject(ecmaVm); - reply->Set(ecmaVm, StringRef::NewFromUtf8(ecmaVm, "id"), IntegerRef::New(ecmaVm, request.GetCallId())); - Local resultObj; - if (response.IsOk() && result != nullptr) { - resultObj = result->ToObject(ecmaVm); + std::unique_ptr reply = PtJson::CreateObject(); + reply->Add("id", request.GetCallId()); + std::unique_ptr resultObj; + if (response.IsOk()) { + resultObj = result.ToJson(); } else { - resultObj = CreateErrorReply(ecmaVm, response); + resultObj = CreateErrorReply(response); } - reply->Set(ecmaVm, StringRef::NewFromUtf8(ecmaVm, "result"), Local(resultObj)); - SendReply(ecmaVm, reply); + reply->Add("result", resultObj); + SendReply(*reply); } -void ProtocolHandler::SendNotification(const EcmaVM *ecmaVm, std::unique_ptr events) +void ProtocolHandler::SendNotification(const PtBaseEvents &events) { - if (!ecmaVm->GetJsDebuggerManager()->IsDebugMode() || events == nullptr) { - return; - } - LOG(DEBUG, DEBUGGER) << "ProtocolHandler::SendNotification: " << events->GetName(); - SendReply(ecmaVm, events->ToObject(ecmaVm)); + LOG(DEBUG, DEBUGGER) << "ProtocolHandler::SendNotification: " << events.GetName(); + SendReply(*events.ToJson()); } -void ProtocolHandler::SendReply(const EcmaVM *ecmaVm, Local reply) +void ProtocolHandler::SendReply(const PtJson &reply) { - Local str = JSON::Stringify(ecmaVm, reply); - if (str->IsException()) { - DebuggerApi::ClearException(ecmaVm); - LOG(ERROR, DEBUGGER) << "json stringifier throw exception"; - return; - } - if (!str->IsString()) { + std::string str = reply.Stringify(); + if (str.empty()) { LOG(ERROR, DEBUGGER) << "ProtocolHandler::SendReply: json stringify error"; return; } - callback_(StringRef::Cast(*str)->ToString()); + callback_(str); } -Local ProtocolHandler::CreateErrorReply(const EcmaVM *ecmaVm, const DispatchResponse &response) +std::unique_ptr ProtocolHandler::CreateErrorReply(const DispatchResponse &response) { - Local result = PtBaseTypes::NewObject(ecmaVm); + std::unique_ptr result = PtJson::CreateObject(); if (!response.IsOk()) { - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "code")), - IntegerRef::New(ecmaVm, static_cast(response.GetError()))); - result->Set(ecmaVm, - Local(StringRef::NewFromUtf8(ecmaVm, "message")), - Local(StringRef::NewFromUtf8(ecmaVm, response.GetMessage().c_str()))); + result->Add("code", static_cast(response.GetError())); + result->Add("message", response.GetMessage().c_str()); } return result; diff --git a/ecmascript/tooling/protocol_handler.h b/ecmascript/tooling/protocol_handler.h index 6373311cb21cb0ce05aa136f6ac3bec8d475d7ec..08b44e89b28c1b86d6be234fe4c7fe546168feb9 100644 --- a/ecmascript/tooling/protocol_handler.h +++ b/ecmascript/tooling/protocol_handler.h @@ -20,33 +20,30 @@ #include #include -#include "ecmascript/tooling/front_end.h" +#include "ecmascript/tooling/protocol_channel.h" namespace panda::ecmascript::tooling { -class ProtocolHandler final : public FrontEnd { +class ProtocolHandler final : public ProtocolChannel { public: - explicit ProtocolHandler(std::function callback, const EcmaVM *vm); + ProtocolHandler(std::function callback, const EcmaVM *vm) + : callback_(std::move(callback)), dispatcher_(vm, this), vm_(vm) {} ~ProtocolHandler() override = default; void WaitForDebugger() override; void RunIfWaitingForDebugger() override; - void ProcessCommand(const CString &msg); + void ProcessCommand(const std::string &msg); void SendResponse(const DispatchRequest &request, const DispatchResponse &response, - std::unique_ptr result) override; - void SendNotification(const EcmaVM *ecmaVm, std::unique_ptr events) override; - const EcmaVM *GetEcmaVM() const - { - return vm_; - } + const PtBaseReturns &result) override; + void SendNotification(const PtBaseEvents &events) override; private: NO_MOVE_SEMANTIC(ProtocolHandler); NO_COPY_SEMANTIC(ProtocolHandler); - Local CreateErrorReply(const EcmaVM *ecmaVm, const DispatchResponse &response); - void SendReply(const EcmaVM *ecmaVm, Local reply); + std::unique_ptr CreateErrorReply(const DispatchResponse &response); + void SendReply(const PtJson &reply); std::function callback_; - std::unique_ptr dispatcher_ {}; + Dispatcher dispatcher_; bool waitingForDebugger_ {false}; const EcmaVM *vm_ {nullptr}; diff --git a/ecmascript/tooling/test/BUILD.gn b/ecmascript/tooling/test/BUILD.gn index d1247b0ff5f121db3788c8dd9da431b575e4287c..1155984448065366661d6d7ae3a5779a63887345 100644 --- a/ecmascript/tooling/test/BUILD.gn +++ b/ecmascript/tooling/test/BUILD.gn @@ -22,10 +22,20 @@ module_output_path = "ark/js_runtime" config("debug_api_test") { visibility = [ ":*" ] - cflags_cc = [ "-Wno-gnu-zero-variadic-macro-arguments" ] ldflags = [ "-Wl,-rpath=\$ORIGIN/" ] + + configs = [ + "//ark/js_runtime:ark_jsruntime_public_config", # should add before + # arkruntime_public_config + "//ark/js_runtime:ark_jsruntime_common_config", + "//ark/js_runtime:ecma_test_config", + "$ark_root/runtime:arkruntime_public_config", + ] + include_dirs = [ "//ark/js_runtime", + "//ark/runtime_core", + "//ark/runtime_core/libpandabase", "//ark/js_runtime/ecmascript/tooling/test", ] } @@ -42,6 +52,30 @@ ts2abc_gen_abc("ark_sample_abc") { out_puts = [ test_abc_path ] } +ts2abc_gen_abc("ark_asyncfunc_abc") { + test_js_path = "//ark/js_runtime/ecmascript/tooling/test/js/AsyncFunc.js" + test_abc_path = "$target_out_dir/AsyncFunc.abc" + extra_visibility = [ ":*" ] # Only targets in this file can depend on this. + src_js = rebase_path(test_js_path) + dst_file = rebase_path(test_abc_path) + extra_args = [ "--debug" ] + + in_puts = [ test_js_path ] + out_puts = [ test_abc_path ] +} + +ts2abc_gen_abc("ark_arrowfunc_abc") { + test_js_path = "//ark/js_runtime/ecmascript/tooling/test/js/ArrowFunc.js" + test_abc_path = "$target_out_dir/ArrowFunc.abc" + extra_visibility = [ ":*" ] # Only targets in this file can depend on this. + src_js = rebase_path(test_js_path) + dst_file = rebase_path(test_abc_path) + extra_args = [ "--debug" ] + + in_puts = [ test_js_path ] + out_puts = [ test_abc_path ] +} + ts2abc_gen_abc("ark_exception_abc") { test_js_path = "//ark/js_runtime/ecmascript/tooling/test/js/exception.js" test_abc_path = "$target_out_dir/exception.abc" @@ -54,34 +88,32 @@ ts2abc_gen_abc("ark_exception_abc") { out_puts = [ test_abc_path ] } -ohos_shared_library("debugger_entry") { +source_set("debugger_entry_set") { 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", - ] + public_configs = [ ":debug_api_test" ] deps = [ + ":ark_arrowfunc_abc", + ":ark_asyncfunc_abc", ":ark_exception_abc", ":ark_sample_abc", ":jsdebugtest", "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", ] +} - if (!is_standard_system) { - deps += [ "$ark_root/runtime:libarkruntime" ] - } +ohos_shared_library("debugger_entry") { + deps = [ ":debugger_entry_set" ] + + install_enable = false output_extension = "so" subsystem_name = "test" } -ohos_shared_library("jsdebugtest") { +source_set("jsdebugtest_set") { sources = [ "utils/test_entry.cpp", "utils/test_extractor.cpp", @@ -89,22 +121,29 @@ ohos_shared_library("jsdebugtest") { "utils/testcases/test_list.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", - ] + public_configs = [ ":debug_api_test" ] + + test_abc_dir = "/data/test/" + target_label = get_label_info(":${target_name}", "label_with_toolchain") + target_toolchain = get_label_info(target_label, "toolchain") + if (target_toolchain == host_toolchain) { + test_abc_dir = rebase_path(target_out_dir) + } + + defines = [ "DEBUGGER_ABC_DIR=\"${test_abc_dir}/\"" ] deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", - "//ark/js_runtime:libark_jsruntime_test_static", - "//ark/js_runtime/ecmascript/tooling:libark_ecma_debugger_test_static", + "//ark/js_runtime:libark_jsruntime_test_set", + "//ark/js_runtime/ecmascript/tooling:libark_ecma_debugger_test_set", ] +} + +ohos_shared_library("jsdebugtest") { + deps = [ ":jsdebugtest_set" ] - if (!is_linux) { + if (is_ohos && is_standard_system) { if (build_public_version) { external_deps = [ "bytrace_standard:bytrace_core", @@ -119,151 +158,59 @@ ohos_shared_library("jsdebugtest") { deps += [ "$ark_root/runtime:libarkruntime" ] } + install_enable = false + output_extension = "so" subsystem_name = "test" } -ohos_unittest("EcmaDebugApiTest") { +host_unittest_action("DebuggerEntryTest") { module_out_path = module_output_path sources = [ # test file - "debugger_api_test.cpp", + "debugger_entry_test.cpp", ] - resource_config_file = - "//ark/js_runtime/test/resource/js_runtime/ohos_test.xml" + cflags_cc = [ "-Wno-gnu-zero-variadic-macro-arguments" ] + defines = [ "DEBUGGER_TEST_LIBRARY=\"libdebugger_entry.so\"" ] - 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", - ] + configs = [ ":debug_api_test" ] deps = [ - ":debugger_api_resource", + ":debugger_entry_resource", ":jsdebugtest", "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", ] - - if (!is_standard_system) { - deps += [ "$ark_root/runtime:libarkruntime" ] - } } -host_unittest_action("DebuggerCommandsTest") { +host_unittest_action("DebuggerTest") { module_out_path = module_output_path sources = [ # test file "debugger_commands_test.cpp", - ] - - configs = [ - "//ark/js_runtime:ecma_test_config", - "//ark/js_runtime:ark_jsruntime_public_config", # should add before - # arkruntime_public_config - "//ark/js_runtime:ark_jsruntime_common_config", - "$ark_root/runtime:arkruntime_public_config", - ] - - deps = [ - "$ark_root/libpandabase:libarkbase", - "//ark/js_runtime/ecmascript/tooling:libark_ecma_debugger_test", - sdk_libc_secshared_dep, - ] - - if (!is_standard_system) { - deps += [ "$ark_root/runtime:libarkruntime" ] - } -} - -host_unittest_action("DebuggerScriptTest") { - module_out_path = module_output_path - - sources = [ - # test file - "debugger_script_test.cpp", - ] - - configs = [ - "//ark/js_runtime:ecma_test_config", - "//ark/js_runtime:ark_jsruntime_public_config", # should add before - # arkruntime_public_config - "//ark/js_runtime:ark_jsruntime_common_config", - "$ark_root/runtime:arkruntime_public_config", - ] - - deps = [ - "$ark_root/libpandabase:libarkbase", - "//ark/js_runtime/ecmascript/tooling:libark_ecma_debugger_test", - sdk_libc_secshared_dep, - ] - - if (!is_standard_system) { - deps += [ "$ark_root/runtime:libarkruntime" ] - } -} - -host_unittest_action("DebuggerEventsTest") { - module_out_path = module_output_path - - sources = [ - # test file "debugger_events_test.cpp", - ] - - configs = [ - "//ark/js_runtime:ecma_test_config", - "//ark/js_runtime:ark_jsruntime_public_config", # should add before - # arkruntime_public_config - "//ark/js_runtime:ark_jsruntime_common_config", - "$ark_root/runtime:arkruntime_public_config", - ] - - deps = [ - "$ark_root/libpandabase:libarkbase", - "//ark/js_runtime/ecmascript/tooling:libark_ecma_debugger_test", - sdk_libc_secshared_dep, - ] - - if (!is_standard_system) { - deps += [ "$ark_root/runtime:libarkruntime" ] - } -} - -host_unittest_action("DebuggerTypesTest") { - module_out_path = module_output_path - - sources = [ - # test file + "debugger_params_test.cpp", + "debugger_returns_test.cpp", + "debugger_script_test.cpp", "debugger_types_test.cpp", + "js_pt_hooks_test.cpp", + "pt_json_test.cpp", ] - configs = [ - "//ark/js_runtime:ecma_test_config", - "//ark/js_runtime:ark_jsruntime_public_config", # should add before - # arkruntime_public_config - "//ark/js_runtime:ark_jsruntime_common_config", - "$ark_root/runtime:arkruntime_public_config", - ] + configs = [ "//ark/js_runtime:ecma_test_config" ] deps = [ "$ark_root/libpandabase:libarkbase", "//ark/js_runtime/ecmascript/tooling:libark_ecma_debugger_test", sdk_libc_secshared_dep, ] - - if (!is_standard_system) { - deps += [ "$ark_root/runtime:libarkruntime" ] - } } -group("debugger_api_resource") { +group("debugger_entry_resource") { testonly = true deps = [ ":debugger_entry" ] @@ -274,10 +221,8 @@ group("unittest") { # deps file deps = [ - ":DebuggerCommandsTest", - ":DebuggerEventsTest", - ":DebuggerScriptTest", - ":DebuggerTypesTest", + ":DebuggerEntryTest", + ":DebuggerTest", ] } @@ -286,9 +231,7 @@ group("host_unittest") { # deps file deps = [ - ":DebuggerCommandsTestAction", - ":DebuggerEventsTestAction", - ":DebuggerScriptTestAction", - ":DebuggerTypesTestAction", + ":DebuggerEntryTestAction", + ":DebuggerTestAction", ] } diff --git a/ecmascript/tooling/test/debugger_commands_test.cpp b/ecmascript/tooling/test/debugger_commands_test.cpp index f2924766d9b15ec204f6670eca8798ee02f09efe..2ef97abb6690b71d2903f778d51ea62e9547c75f 100644 --- a/ecmascript/tooling/test/debugger_commands_test.cpp +++ b/ecmascript/tooling/test/debugger_commands_test.cpp @@ -21,11 +21,10 @@ #include "ecmascript/tooling/base/pt_returns.h" #include "ecmascript/tooling/debugger_service.h" #include "ecmascript/tooling/dispatcher.h" -#include "ecmascript/tooling/interface/js_debugger.h" +#include "ecmascript/tooling/backend/js_debugger.h" using namespace panda::ecmascript; using namespace panda::ecmascript::tooling; -using namespace panda::tooling; namespace panda::test { class DebuggerCommandsTest : public testing::Test { diff --git a/ecmascript/tooling/test/debugger_api_test.cpp b/ecmascript/tooling/test/debugger_entry_test.cpp similarity index 71% rename from ecmascript/tooling/test/debugger_api_test.cpp rename to ecmascript/tooling/test/debugger_entry_test.cpp index 97762c1e54eb621b43de751445271e2fe2700b0f..bc4fbefdd8f9952d5c0200e1d3500d1fe1d819e7 100644 --- a/ecmascript/tooling/test/debugger_api_test.cpp +++ b/ecmascript/tooling/test/debugger_entry_test.cpp @@ -21,7 +21,7 @@ namespace panda::ecmascript::tooling::test { using panda::test::TestHelper; -class DebuggerApiTest : public testing::TestWithParam { +class DebuggerEntryTest : public testing::TestWithParam { public: static void SetUpTestCase() { @@ -36,33 +36,32 @@ public: void SetUp() override { SetCurrentTestName(GetParam()); - TestHelper::CreateEcmaVMWithScope(instance, thread, scope, DEBUGGER_TEST_LIBRARY); + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + ecmaVm = static_cast(instance); + JSNApi::StartDebugger(DEBUGGER_TEST_LIBRARY, ecmaVm, true); } void TearDown() override { - TestHelper::DestroyEcmaVMWithScope(instance, scope); + JSNApi::StopDebugger(ecmaVm); + TestHelper::DestroyEcmaVMWithScope(ecmaVm, scope); } + EcmaVM *ecmaVm {nullptr}; PandaVM *instance {nullptr}; EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; }; -HWTEST_P_L0(DebuggerApiTest, EcmaScriptSuite) +HWTEST_P_L0(DebuggerEntryTest, DebuggerSuite) { - const char *testName = GetCurrentTestName(); + std::string testName = GetCurrentTestName(); std::cout << "Running " << testName << std::endl; - EcmaVM *vm = EcmaVM::Cast(instance); - ASSERT_NE(vm, nullptr); + ASSERT_NE(ecmaVm, nullptr); auto [pandaFile, entryPoint] = GetTestEntryPoint(testName); - - std::string fileNameStr(pandaFile); - std::string entryStr(entryPoint); - auto res = JSNApi::Execute(vm, fileNameStr, entryStr); + auto res = JSNApi::Execute(ecmaVm, pandaFile.c_str(), entryPoint.c_str()); ASSERT_TRUE(res); } -INSTANTIATE_TEST_CASE_P(EcmaDebugApiTest, DebuggerApiTest, - testing::ValuesIn(GetTestList(panda::panda_file::SourceLang::ECMASCRIPT))); +INSTANTIATE_TEST_CASE_P(DebugAbcTest, DebuggerEntryTest, testing::ValuesIn(GetTestList())); } // namespace panda::ecmascript::tooling::test diff --git a/ecmascript/tooling/test/debugger_events_test.cpp b/ecmascript/tooling/test/debugger_events_test.cpp index 9d8615815f42b669303f373a63f0bb2eb9c81293..9f0ea0207530c2a45a15272127c6e8fad16e1447 100644 --- a/ecmascript/tooling/test/debugger_events_test.cpp +++ b/ecmascript/tooling/test/debugger_events_test.cpp @@ -62,144 +62,40 @@ protected: JSThread *thread {nullptr}; }; -HWTEST_F_L0(DebuggerEventsTest, BreakpointResolvedCreateTest) +HWTEST_F_L0(DebuggerEventsTest, BreakpointResolvedToJsonTest) { - CString msg; - std::unique_ptr breakpointResolved; - - // abnormal params of null msg - msg = CString() + R"({})"; - breakpointResolved = BreakpointResolved::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(breakpointResolved, nullptr); - - // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - breakpointResolved = BreakpointResolved::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(breakpointResolved, nullptr); - - // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - breakpointResolved = BreakpointResolved::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(breakpointResolved, nullptr); - - // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - breakpointResolved = BreakpointResolved::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(breakpointResolved, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"breakpointId":"00"}})"; - breakpointResolved = BreakpointResolved::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(breakpointResolved, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"location":{"scriptId":"id2","lineNumber":99}}})"; - breakpointResolved = BreakpointResolved::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(breakpointResolved, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"breakpointId":"00", - "location":{"scriptId":"id2","lineNumber":99}}})"; - breakpointResolved = BreakpointResolved::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(breakpointResolved, nullptr); -} - -HWTEST_F_L0(DebuggerEventsTest, BreakpointResolvedToObjectTest) -{ - CString msg; - std::unique_ptr breakpointResolved; - Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"breakpointId":"00", - "location":{"scriptId":"id2","lineNumber":99}}})"; - breakpointResolved = BreakpointResolved::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - - ASSERT_NE(breakpointResolved, nullptr); - Local object1 = breakpointResolved->ToObject(ecmaVm); - Local result = object1->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - Local object = Local(result); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "breakpointId"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("00", Local(result)->ToString()); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "location"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); -} - -HWTEST_F_L0(DebuggerEventsTest, PausedCreateTest) -{ - CString msg; - std::unique_ptr paused; - - // abnormal params of null msg - msg = CString() + R"({})"; - paused = Paused::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(paused, nullptr); - - // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - paused = Paused::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(paused, nullptr); - - // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - paused = Paused::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(paused, nullptr); - - // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - paused = Paused::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(paused, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"reason":"exception"}})"; - paused = Paused::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(paused, nullptr); - - msg = CString() + - R"({"id":0,"method":"Debugger.Test","params": - {"callFrames":[)" + - R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":10,"functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": - [{"type":"global","object":{"type":")" + - ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + - R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})" + - R"(]}})"; - paused = Paused::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(paused, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"callFrames":[)" + - R"({"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": - [{"type":"global","object":{"type":")" + - ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + - R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}})" + - R"(],"reason":"exception"}})"; - paused = Paused::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(paused, nullptr); + BreakpointResolved breakpointResolved; + + auto location = std::make_unique(); + location->SetScriptId(2).SetLine(99); + breakpointResolved.SetBreakpointId("00").SetLocation(std::move(location)); + + std::unique_ptr json; + ASSERT_EQ(breakpointResolved.ToJson()->GetObject("params", &json), Result::SUCCESS); + std::string breakpointId; + ASSERT_EQ(json->GetString("breakpointId", &breakpointId), Result::SUCCESS); + EXPECT_EQ(breakpointId, "00"); + + std::unique_ptr locationJson; + ASSERT_EQ(json->GetObject("location", &locationJson), Result::SUCCESS); + std::string scriptId; + ASSERT_EQ(locationJson->GetString("scriptId", &scriptId), Result::SUCCESS); + EXPECT_EQ(scriptId, "2"); + int32_t lineNumber; + ASSERT_EQ(locationJson->GetInt("lineNumber", &lineNumber), Result::SUCCESS); + EXPECT_EQ(lineNumber, 99); } +#ifdef CHANGE_TOJSON HWTEST_F_L0(DebuggerEventsTest, PausedToObjectTest) { - CString msg; - std::unique_ptr paused; + Paused paused; Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"callFrames":[{"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7", - "scopeChain":[{"type":"global","object":{"type":"object"}}, {"type":"local","object":{"type":"object"}}], - "this":{"type":"object","subtype":"v128"}}],"reason":"exception"}})"; - paused = Paused::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(paused, nullptr); - - Local object1 = paused->ToObject(ecmaVm); + std::vector> v; + paused.SetCallFrames(std::move(v)) + .SetReason(PauseReason::EXCEPTION); + Local object1 = paused.ToObject(ecmaVm); Local result = object1->Get(ecmaVm, tmpStr); ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); ASSERT_TRUE(result->IsObject()); @@ -220,17 +116,16 @@ HWTEST_F_L0(DebuggerEventsTest, PausedToObjectTest) HWTEST_F_L0(DebuggerEventsTest, ResumedToObjectTest) { - CString msg; - std::unique_ptr resumed = std::make_unique(); + Resumed resumed; Local tmpStr; - Local object = resumed->ToObject(ecmaVm); + Local object = resumed.ToObject(ecmaVm); tmpStr = StringRef::NewFromUtf8(ecmaVm, "method"); ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); Local result = object->Get(ecmaVm, tmpStr); ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(std::string(resumed->GetName().c_str()), Local(result)->ToString()); + EXPECT_EQ(resumed.GetName(), Local(result)->ToString()); tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); @@ -239,318 +134,27 @@ HWTEST_F_L0(DebuggerEventsTest, ResumedToObjectTest) ASSERT_TRUE(result->IsObject()); } -HWTEST_F_L0(DebuggerEventsTest, ScriptFailedToParseCreateTest) -{ - CString msg; - std::unique_ptr parse; - - // abnormal params of null msg - msg = CString() + R"({})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn:"10}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js"}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00"}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001"}})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true, - "length":34, - "stackTrace":{"callFrames":[{"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7", - "scopeChain":[{"type":"global","object":{"type":"object"}}, {"type":"local","object":{"type":"object"}}], - "this":{"type":"object","subtype":"v128"}}]}, - "codeOffset":432, - "scriptLanguage":"JavaScript" - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true, - "length":34, - "stackTrace":{"callFrames":[{"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7", - "scopeChain":[{"type":"global","object":{"type":"object"}}, {"type":"local","object":{"type":"object"}}], - "this":{"type":"object","subtype":"v128"}}]}, - "codeOffset":432 - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true, - "length":34, - "stackTrace":{"callFrames":[{"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7", - "scopeChain":[{"type":"global","object":{"type":"object"}}, {"type":"local","object":{"type":"object"}}], - "this":{"type":"object","subtype":"v128"}}]} - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true, - "length":34 - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/", - "hasSourceURL":true - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/" - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1} - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001" - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true, - "length":34, - "stackTrace":{"callFrames":[{"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7", - "scopeChain":[{"type":"global","object":{"type":"object"}}, {"type":"local","object":{"type":"object"}}], - "this":{"type":"object","subtype":"v128"}}]}, - "codeOffset":432, - "scriptLanguage":"JavaScript", - "embedderName":"hh" - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); -} - HWTEST_F_L0(DebuggerEventsTest, ScriptFailedToParseToObjectTest) { - CString msg; - std::unique_ptr parse; + ScriptFailedToParse parsed; Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true, - "length":34, - "stackTrace":{"callFrames":[{"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7", - "scopeChain":[{"type":"global","object":{"type":"object"}}, {"type":"local","object":{"type":"object"}}], - "this":{"type":"object","subtype":"v128"}}]}, - "codeOffset":432, - "scriptLanguage":"JavaScript", - "embedderName":"hh" - }})"; - parse = ScriptFailedToParse::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - Local object1 = parse->ToObject(ecmaVm); + parsed.SetScriptId(100) + .SetUrl("use/test.js") + .SetStartLine(0) + .SetStartColumn(4) + .SetEndLine(10) + .SetEndColumn(10) + .SetExecutionContextId(2) + .SetHash("hash0001") + .SetSourceMapURL("usr/") + .SetHasSourceURL(true) + .SetIsModule(true) + .SetLength(34) + .SetCodeOffset(432) + .SetScriptLanguage("JavaScript") + .SetEmbedderName("hh"); + Local object1 = parsed.ToObject(ecmaVm); Local result = object1->Get(ecmaVm, tmpStr); ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); ASSERT_TRUE(result->IsObject()); @@ -560,7 +164,7 @@ HWTEST_F_L0(DebuggerEventsTest, ScriptFailedToParseToObjectTest) ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); result = object->Get(ecmaVm, tmpStr); ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("00", Local(result)->ToString()); + EXPECT_EQ("100", Local(result)->ToString()); tmpStr = StringRef::NewFromUtf8(ecmaVm, "url"); ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); @@ -605,10 +209,7 @@ HWTEST_F_L0(DebuggerEventsTest, ScriptFailedToParseToObjectTest) EXPECT_EQ("hash0001", Local(result)->ToString()); tmpStr = StringRef::NewFromUtf8(ecmaVm, "executionContextAuxData"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); + ASSERT_FALSE(object->Has(ecmaVm, tmpStr)); tmpStr = StringRef::NewFromUtf8(ecmaVm, "sourceMapURL"); ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); @@ -653,158 +254,28 @@ HWTEST_F_L0(DebuggerEventsTest, ScriptFailedToParseToObjectTest) EXPECT_EQ("hh", Local(result)->ToString()); } -HWTEST_F_L0(DebuggerEventsTest, ScriptParsedCreateTest) -{ - CString msg; - std::unique_ptr parse; - - // abnormal params of null msg - msg = CString() + R"({})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn:"10}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js"}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00"}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001"}})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(parse, nullptr); - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "isLiveEdit":true, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true, - "length":34, - "stackTrace":{"callFrames":[{"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7", - "scopeChain":[{"type":"global","object":{"type":"object"}}, {"type":"local","object":{"type":"object"}}], - "this":{"type":"object","subtype":"v128"}}]}, - "codeOffset":432, - "scriptLanguage":"JavaScript", - "embedderName":"hh" - }})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); -} - HWTEST_F_L0(DebuggerEventsTest, ScriptParsedToObjectTest) { - CString msg; - std::unique_ptr parse; + ScriptParsed parsed; Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); - msg = CString() + R"({"id":0,"method":"Debugger.Test","params": - {"scriptId":"00", - "url":"use/test.js", - "startLine":0, - "startColumn":4, - "endLine":10, - "endColumn":10, - "executionContextId":2, - "hash":"hash0001", - "executionContextAuxData":{"a":1}, - "isLiveEdit":true, - "sourceMapURL":"usr/", - "hasSourceURL":true, - "isModule":true, - "length":34, - "stackTrace":{"callFrames":[{"callFrameId":"10","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7", - "scopeChain":[{"type":"global","object":{"type":"object"}}, {"type":"local","object":{"type":"object"}}], - "this":{"type":"object","subtype":"v128"}}]}, - "codeOffset":432, - "scriptLanguage":"JavaScript", - "embedderName":"hh" - }})"; - parse = ScriptParsed::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - ASSERT_NE(parse, nullptr); - - Local object1 = parse->ToObject(ecmaVm); + parsed.SetScriptId(10) + .SetUrl("use/test.js") + .SetStartLine(0) + .SetStartColumn(4) + .SetEndLine(10) + .SetEndColumn(10) + .SetExecutionContextId(2) + .SetHash("hash0001") + .SetIsLiveEdit(true) + .SetSourceMapURL("usr/") + .SetHasSourceURL(true) + .SetIsModule(true) + .SetLength(34) + .SetCodeOffset(432) + .SetScriptLanguage("JavaScript") + .SetEmbedderName("hh"); + Local object1 = parsed.ToObject(ecmaVm); Local result = object1->Get(ecmaVm, tmpStr); ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); ASSERT_TRUE(result->IsObject()); @@ -814,7 +285,7 @@ HWTEST_F_L0(DebuggerEventsTest, ScriptParsedToObjectTest) ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); result = object->Get(ecmaVm, tmpStr); ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("00", Local(result)->ToString()); + EXPECT_EQ("10", Local(result)->ToString()); tmpStr = StringRef::NewFromUtf8(ecmaVm, "url"); ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); @@ -859,10 +330,7 @@ HWTEST_F_L0(DebuggerEventsTest, ScriptParsedToObjectTest) EXPECT_EQ("hash0001", Local(result)->ToString()); tmpStr = StringRef::NewFromUtf8(ecmaVm, "executionContextAuxData"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); + ASSERT_FALSE(object->Has(ecmaVm, tmpStr)); tmpStr = StringRef::NewFromUtf8(ecmaVm, "isLiveEdit"); ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); @@ -912,4 +380,189 @@ HWTEST_F_L0(DebuggerEventsTest, ScriptParsedToObjectTest) ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); EXPECT_EQ("hh", Local(result)->ToString()); } + +HWTEST_F_L0(DebuggerEventsTest, ConsoleProfileFinishedToObjectTest) +{ + ConsoleProfileFinished consoleProfileFinished; + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); + + auto location = std::make_unique(); + location->SetScriptId(13).SetLine(20); + std::vector> v; + auto profile = std::make_unique(); + profile->SetNodes(std::move(v)) + .SetStartTime(0) + .SetEndTime(15) + .SetSamples(std::vector{}) + .SetTimeDeltas(std::vector{}); + consoleProfileFinished.SetId("11").SetLocation(std::move(location)).SetProfile(std::move(profile)).SetTitle("001"); + Local object1 = consoleProfileFinished.ToObject(ecmaVm); + Local result = object1->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsObject()); + Local object = Local(result); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "id"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->ToString(), "11"); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "location"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsObject()); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "profile"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsObject()); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "title"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->ToString(), "001"); +} + +HWTEST_F_L0(DebuggerEventsTest, ConsoleProfileStartedToObjectTest) +{ + ConsoleProfileStarted consoleProfileStarted; + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); + + auto location = std::make_unique(); + location->SetScriptId(17).SetLine(30); + consoleProfileStarted.SetId("12").SetLocation(std::move(location)).SetTitle("002"); + Local object1 = consoleProfileStarted.ToObject(ecmaVm); + Local result = object1->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsObject()); + Local object = Local(result); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "id"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->ToString(), "12"); + + Local tmpObject = consoleProfileStarted.GetLocation()->ToObject(ecmaVm); + tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptId"); + ASSERT_TRUE(tmpObject->Has(ecmaVm, tmpStr)); + Local tmpResult = tmpObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!tmpResult.IsEmpty() && !tmpResult->IsUndefined()); + EXPECT_EQ(Local(tmpResult)->ToString(), "17"); + tmpStr = StringRef::NewFromUtf8(ecmaVm, "lineNumber"); + ASSERT_TRUE(tmpObject->Has(ecmaVm, tmpStr)); + tmpResult = tmpObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!tmpResult.IsEmpty() && !tmpResult->IsUndefined()); + EXPECT_EQ(Local(tmpResult)->Value(), 30); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "title"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->ToString(), "002"); +} + +HWTEST_F_L0(DebuggerEventsTest, PreciseCoverageDeltaUpdateToObjectTest) +{ + PreciseCoverageDeltaUpdate preciseCoverageDeltaUpdate; + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); + + std::vector> v; + preciseCoverageDeltaUpdate.SetOccasion("percise") + .SetResult(std::move(v)) + .SetTimestamp(77); + Local object1 = preciseCoverageDeltaUpdate.ToObject(ecmaVm); + Local result = object1->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsObject()); + Local object = Local(result); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "timestamp"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->Value(), 77); + tmpStr = StringRef::NewFromUtf8(ecmaVm, "occasion"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->ToString(), "percise"); + tmpStr = StringRef::NewFromUtf8(ecmaVm, "result"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsArray(ecmaVm)); +} + +HWTEST_F_L0(DebuggerEventsTest, HeapStatsUpdateToObjectTest) +{ + HeapStatsUpdate heapStatsUpdate; + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); + + heapStatsUpdate.SetStatsUpdate(std::vector {}); + Local object1 = heapStatsUpdate.ToObject(ecmaVm); + Local result = object1->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsObject()); + Local object = Local(result); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "statsUpdate"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsArray(ecmaVm)); +} + +HWTEST_F_L0(DebuggerEventsTest, LastSeenObjectIdToObjectTest) +{ + LastSeenObjectId lastSeenObjectId; + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); + + lastSeenObjectId.SetLastSeenObjectId(10).SetTimestamp(77); + Local object1 = lastSeenObjectId.ToObject(ecmaVm); + Local result = object1->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsObject()); + Local object = Local(result); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "lastSeenObjectId"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->Value(), 10); + tmpStr = StringRef::NewFromUtf8(ecmaVm, "timestamp"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->Value(), 77); +} + +HWTEST_F_L0(DebuggerEventsTest, ReportHeapSnapshotProgressToObjectTest) +{ + ReportHeapSnapshotProgress reportHeapSnapshotProgress; + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "params"); + + reportHeapSnapshotProgress.SetDone(10).SetTotal(100); + Local object1 = reportHeapSnapshotProgress.ToObject(ecmaVm); + Local result = object1->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsObject()); + Local object = Local(result); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "done"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->Value(), 10); + tmpStr = StringRef::NewFromUtf8(ecmaVm, "total"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->Value(), 100); +} +#endif } // namespace panda::test \ No newline at end of file diff --git a/ecmascript/tooling/test/debugger_params_test.cpp b/ecmascript/tooling/test/debugger_params_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30a21726f3fbe2ab8c5f2ae160dcf4c933c1e51c --- /dev/null +++ b/ecmascript/tooling/test/debugger_params_test.cpp @@ -0,0 +1,373 @@ +/* + * 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/js_array.h" +#include "ecmascript/js_object-inl.h" +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/tests/test_helper.h" +#include "ecmascript/tooling/base/pt_types.h" +#include "ecmascript/tooling/base/pt_params.h" +#include "ecmascript/tooling/dispatcher.h" + +using namespace panda::ecmascript; +using namespace panda::ecmascript::tooling; + +namespace panda::test { +// Duplicate name of panda::ecmascript::PropertyDescriptor in js_object-inl.h +using panda::ecmascript::tooling::PropertyDescriptor; + +using ObjectType = RemoteObject::TypeName; +using ObjectSubType = RemoteObject::SubTypeName; +using ObjectClassName = RemoteObject::ClassName; + +class DebuggerParamsTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + Logger::InitializeStdLogging(Logger::Level::FATAL, LoggerComponentMaskAll); + } + + static void TearDownTestCase() + { + Logger::InitializeStdLogging(Logger::Level::ERROR, LoggerComponentMaskAll); + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + ecmaVm = EcmaVM::Cast(instance); + // Main logic is JSON parser, so not need trigger GC to decrease execute time + ecmaVm->SetEnableForceGC(false); + } + + void TearDown() override + { + TestHelper::DestroyEcmaVMWithScope(ecmaVm, scope); + } + +protected: + EcmaVM *ecmaVm {nullptr}; + PandaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +}; + +HWTEST_F_L0(DebuggerParamsTest, EnableParamsCreateTest) +{ + std::string msg; + std::unique_ptr enableParams; + + // abnormal + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + enableParams = EnableParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(enableParams, nullptr); + EXPECT_FALSE(enableParams->HasMaxScriptsCacheSize()); + + // normal + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"maxScriptsCacheSize":100}})"; + enableParams = EnableParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(enableParams, nullptr); + EXPECT_EQ(enableParams->GetMaxScriptsCacheSize(), 100); +} + + +#ifdef SUPPORT_PROFILER_CDP +HWTEST_F_L0(DebuggerParamsTest, StartSamplingParamsCreateTest) +{ + std::string msg; + std::unique_ptr startSamplingData; + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + startSamplingData = StartSamplingParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(startSamplingData, nullptr); + EXPECT_EQ(startSamplingData->GetSamplingInterval(), 32768); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + startSamplingData = StartSamplingParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(startSamplingData, nullptr); + EXPECT_EQ(startSamplingData->GetSamplingInterval(), 32768); + + // abnormal params of params.sub-key=["samplingInterval":true] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"samplingInterval":true}})"; + startSamplingData = StartSamplingParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(startSamplingData, nullptr); + + // abnormal params of params.sub-key=["samplingInterval":true] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"samplingInterval":"Test"}})"; + startSamplingData = StartSamplingParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(startSamplingData, nullptr); + + // abnormal params of params.sub-key = [ "size"=100,"nodeId"=1,"ordinal"=10] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"samplingInterval":1000}})"; + startSamplingData = StartSamplingParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(startSamplingData, nullptr); + EXPECT_EQ(startSamplingData->GetSamplingInterval(), 1000); +} + +HWTEST_F_L0(DebuggerParamsTest, StartTrackingHeapObjectsParamsCreateTest) +{ + std::string msg; + std::unique_ptr objectData; + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + objectData = StartTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + ASSERT_FALSE(objectData->GetTrackAllocations()); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + objectData = StartTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + ASSERT_FALSE(objectData->GetTrackAllocations()); + + // abnormal params of params.sub-key=["trackAllocations":10] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"trackAllocations":10}})"; + objectData = StartTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["trackAllocations":"Test"] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"trackAllocations":"Test"}})"; + objectData = StartTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["trackAllocations":true] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"trackAllocations":true}})"; + objectData = StartTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + ASSERT_TRUE(objectData->GetTrackAllocations()); +} + +HWTEST_F_L0(DebuggerParamsTest, StopTrackingHeapObjectsParamsCreateTest) +{ + std::string msg; + std::unique_ptr objectData; + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + objectData = StopTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + ASSERT_FALSE(objectData->GetReportProgress()); + ASSERT_FALSE(objectData->GetTreatGlobalObjectsAsRoots()); + ASSERT_FALSE(objectData->GetCaptureNumericValue()); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + objectData = StopTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + ASSERT_FALSE(objectData->GetReportProgress()); + ASSERT_FALSE(objectData->GetTreatGlobalObjectsAsRoots()); + ASSERT_FALSE(objectData->GetCaptureNumericValue()); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "reportProgress":10, + "treatGlobalObjectsAsRoots":10, + "captureNumericValue":10}})"; + objectData = StopTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "reportProgress":"Test", + "treatGlobalObjectsAsRoots":"Test", + "captureNumericValue":"Test"}})"; + objectData = StopTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "reportProgress":true, + "treatGlobalObjectsAsRoots":true, + "captureNumericValue":true}})"; + objectData = StopTrackingHeapObjectsParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + ASSERT_TRUE(objectData->GetReportProgress()); + ASSERT_TRUE(objectData->GetTreatGlobalObjectsAsRoots()); + ASSERT_TRUE(objectData->GetCaptureNumericValue()); +} + +HWTEST_F_L0(DebuggerParamsTest, AddInspectedHeapObjectParamsCreateTest) +{ + std::string msg; + std::unique_ptr objectData; + + // abnormal params of null msg + msg = std::string() + R"({})"; + objectData = AddInspectedHeapObjectParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + objectData = AddInspectedHeapObjectParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + objectData = AddInspectedHeapObjectParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + objectData = AddInspectedHeapObjectParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["heapObjectId":10] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"heapObjectId":10}})"; + objectData = AddInspectedHeapObjectParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["heapObjectId":true] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"heapObjectId":true}})"; + objectData = AddInspectedHeapObjectParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["heapObjectId":“10”] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"heapObjectId":"10"}})"; + objectData = AddInspectedHeapObjectParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + EXPECT_EQ(objectData->GetHeapObjectId(), 10); +} + +HWTEST_F_L0(DebuggerParamsTest, GetHeapObjectIdParamsCreateTest) +{ + std::string msg; + std::unique_ptr objectData; + + // abnormal params of params.sub-key=["objectId":10] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"objectId":10}})"; + objectData = GetHeapObjectIdParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["objectId":true] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"objectId":true}})"; + objectData = GetHeapObjectIdParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["objectId":“10”] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"objectId":"10"}})"; + objectData = GetHeapObjectIdParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + EXPECT_EQ((int)objectData->GetObjectId(), 10); +} + +HWTEST_F_L0(DebuggerParamsTest, GetObjectByHeapObjectIdParamsCreateTest) +{ + std::string msg; + std::unique_ptr objectData; + + // abnormal params of params.sub-key=["objectId":10] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"objectId":10}})"; + objectData = GetObjectByHeapObjectIdParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["objectId":true] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"objectId":"10", "objectGroup":10}})"; + objectData = GetObjectByHeapObjectIdParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of params.sub-key=["objectId":“10”] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"objectId":"10"}})"; + objectData = GetObjectByHeapObjectIdParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + EXPECT_EQ((int)objectData->GetObjectId(), 10); + ASSERT_FALSE(objectData->HasObjectGroup()); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"objectId":"10", "objectGroup":"groupname"}})"; + objectData = GetObjectByHeapObjectIdParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + EXPECT_EQ((int)objectData->GetObjectId(), 10); + EXPECT_EQ(objectData->GetObjectGroup(), "groupname"); +} + +HWTEST_F_L0(DebuggerParamsTest, StartPreciseCoverageParamCreateTest) +{ + std::string msg; + std::unique_ptr objectData; + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + objectData = StartPreciseCoverageParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + objectData = StartPreciseCoverageParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callCount":8, + "detailed":8, + "allowTriggeredUpdates":8}})"; + objectData = StartPreciseCoverageParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callCount":"Test", + "detailed":"Test", + "allowTriggeredUpdates":"Test"}})"; + objectData = StartPreciseCoverageParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callCount":true, + "detailed":true, + "allowTriggeredUpdates":true}})"; + objectData = StartPreciseCoverageParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + ASSERT_TRUE(objectData->GetCallCount()); + ASSERT_TRUE(objectData->GetDetailed()); + ASSERT_TRUE(objectData->GetAllowTriggeredUpdates()); +} + +HWTEST_F_L0(DebuggerParamsTest, SetSamplingIntervalParamsCreateTest) +{ + std::string msg; + std::unique_ptr objectData; + + // abnormal params of null msg + msg = std::string() + R"({})"; + objectData = SetSamplingIntervalParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + objectData = SetSamplingIntervalParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + objectData = SetSamplingIntervalParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + objectData = SetSamplingIntervalParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "interval":"500"}})"; + objectData = SetSamplingIntervalParams::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(objectData, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"interval":500}})"; + objectData = SetSamplingIntervalParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(objectData, nullptr); + EXPECT_EQ(objectData->GetInterval(), 500); +} +#endif +} // namespace panda::test diff --git a/ecmascript/tooling/test/debugger_returns_test.cpp b/ecmascript/tooling/test/debugger_returns_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f9a325c68f30cd782332af413060c1b8cc5326ed --- /dev/null +++ b/ecmascript/tooling/test/debugger_returns_test.cpp @@ -0,0 +1,391 @@ +/* + * 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/js_array.h" +#include "ecmascript/js_object-inl.h" +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/tests/test_helper.h" +#include "ecmascript/tooling/base/pt_types.h" +#include "ecmascript/tooling/base/pt_returns.h" +#include "ecmascript/tooling/dispatcher.h" + +using namespace panda::ecmascript; +using namespace panda::ecmascript::tooling; + +namespace panda::test { +// Duplicate name of panda::ecmascript::PropertyDescriptor in js_object-inl.h +using panda::ecmascript::tooling::PropertyDescriptor; +using ObjectType = RemoteObject::TypeName; +using ObjectSubType = RemoteObject::SubTypeName; +using ObjectClassName = RemoteObject::ClassName; + +class DebuggerReturnsTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + ecmaVm = EcmaVM::Cast(instance); + } + + void TearDown() override + { + TestHelper::DestroyEcmaVMWithScope(ecmaVm, scope); + } + +protected: + EcmaVM *ecmaVm {nullptr}; + PandaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +}; + +#ifdef CHANGE_TOJSON +HWTEST_F_L0(DebuggerReturnsTest, EnableReturnsToObjectTest) +{ + std::unique_ptr enableReturns = std::make_unique(100U); + ASSERT_NE(enableReturns, nullptr); + Local enableObject = enableReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "debuggerId"); + ASSERT_TRUE(enableObject->Has(ecmaVm, tmpStr)); + Local result = enableObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(std::string("100"), Local(result)->ToString()); +} + +HWTEST_F_L0(DebuggerReturnsTest, SetBreakpointByUrlReturnsToObjectTest) +{ + auto locations = std::vector>(); + std::unique_ptr location = std::make_unique(); + location->SetScriptId(1); + locations.emplace_back(std::move(location)); + ASSERT_EQ(locations.back()->GetScriptId(), 1); + + std::unique_ptr setBreakpointByUrlReturns + = std::make_unique("11", std::move(locations)); + ASSERT_NE(setBreakpointByUrlReturns, nullptr); + Local setObject = setBreakpointByUrlReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "breakpointId"); + ASSERT_TRUE(setObject->Has(ecmaVm, tmpStr)); + Local result = setObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(std::string("11"), Local(result)->ToString()); +} + +HWTEST_F_L0(DebuggerReturnsTest, EvaluateOnCallFrameReturnsToObjectTest) +{ + std::unique_ptr result1 = std::make_unique(); + std::unique_ptr exceptionDetails = std::make_unique(); + std::unique_ptr evaluateOnCallFrameReturns + = std::make_unique(std::move(result1), std::move(exceptionDetails)); + ASSERT_NE(evaluateOnCallFrameReturns, nullptr); + Local callObject = evaluateOnCallFrameReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "result"); + ASSERT_TRUE(callObject->Has(ecmaVm, tmpStr)); + Local result = callObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_EQ(std::move(result1), nullptr); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "exceptionDetails"); + ASSERT_TRUE(callObject->Has(ecmaVm, tmpStr)); + result = callObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_EQ(std::move(exceptionDetails), nullptr); +} + +HWTEST_F_L0(DebuggerReturnsTest, GetPossibleBreakpointsReturnsToObjectTest) +{ + auto locations = std::vector>(); + std::unique_ptr breakLocation = std::make_unique(); + std::unique_ptr getPossibleBreakpointsReturns = std::make_unique + (std::move(locations)); + Local getObject = getPossibleBreakpointsReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "locations"); + ASSERT_TRUE(getObject->Has(ecmaVm, tmpStr)); + Local result = getObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsArray(ecmaVm)); +} + +HWTEST_F_L0(DebuggerReturnsTest, GetScriptSourceReturnsToObjectTest) +{ + std::unique_ptr getScriptSourceReturns = std::make_unique + ("source_1", "bytecode_1"); + ASSERT_NE(getScriptSourceReturns, nullptr); + Local scriptObject = getScriptSourceReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptSource"); + ASSERT_TRUE(scriptObject->Has(ecmaVm, tmpStr)); + Local result = scriptObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(std::string("source_1"), Local(result)->ToString()); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "bytecode"); + ASSERT_TRUE(scriptObject->Has(ecmaVm, tmpStr)); + result = scriptObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(std::string("bytecode_1"), Local(result)->ToString()); +} + +HWTEST_F_L0(DebuggerReturnsTest, RestartFrameReturnsToObjectTest) +{ + auto callFrames = std::vector>(); + std::unique_ptr callFrame = std::make_unique(); + std::unique_ptr restartFrameReturns = std::make_unique + (std::move(callFrames)); + Local restartObject = restartFrameReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "callFrames"); + ASSERT_TRUE(restartObject->Has(ecmaVm, tmpStr)); + Local result = restartObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsArray(ecmaVm)); +} + +HWTEST_F_L0(DebuggerReturnsTest, SetBreakpointReturnsToObjectTest) +{ + std::unique_ptr location = std::make_unique(); + std::unique_ptr setBreakpointReturns + = std::make_unique("breakpointId_1", std::move(location)); + ASSERT_NE(setBreakpointReturns, nullptr); + Local breakObject = setBreakpointReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "breakpointId"); + ASSERT_TRUE(breakObject->Has(ecmaVm, tmpStr)); + Local result = breakObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(std::string("breakpointId_1"), Local(result)->ToString()); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "actualLocation"); + ASSERT_TRUE(breakObject->Has(ecmaVm, tmpStr)); + result = breakObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_EQ(std::move(location), nullptr); +} + +HWTEST_F_L0(DebuggerReturnsTest, SetInstrumentationBreakpointReturnsToObjectTest) +{ + std::unique_ptr setInstrumentationBreakpointReturns + = std::make_unique("111"); + ASSERT_NE(setInstrumentationBreakpointReturns, nullptr); + Local instrumentationObject = setInstrumentationBreakpointReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "breakpointId"); + ASSERT_TRUE(instrumentationObject->Has(ecmaVm, tmpStr)); + Local result = instrumentationObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(std::string("111"), Local(result)->ToString()); +} + +HWTEST_F_L0(DebuggerReturnsTest, SetScriptSourceReturnsToObjectTest) +{ + auto callFrames = std::vector>(); + std::unique_ptr callFrame = std::make_unique(); + std::unique_ptr exceptionDetails = std::make_unique(); + std::unique_ptr setScriptSourceReturns = std::make_unique + (std::move(callFrames)); + Local setObject = setScriptSourceReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "callFrames"); + ASSERT_TRUE(setObject->Has(ecmaVm, tmpStr)); + Local result = setObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsArray(ecmaVm)); + + ASSERT_NE(setScriptSourceReturns, nullptr); + exceptionDetails->SetScriptId(5); + ASSERT_EQ(exceptionDetails->GetScriptId(), 5); +} + +HWTEST_F_L0(DebuggerReturnsTest, GetPropertiesReturnsToObjectTest) +{ + auto descriptor = std::vector>(); + std::unique_ptr propertyDescriptor = std::make_unique(); + std::unique_ptr exceptionDetails = std::make_unique(); + std::unique_ptr getPropertiesReturns = std::make_unique + (std::move(descriptor)); + ASSERT_NE(getPropertiesReturns, nullptr); + exceptionDetails->SetScriptId(6); + ASSERT_EQ(exceptionDetails->GetScriptId(), 6); + + Local getObject = getPropertiesReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "result"); + ASSERT_TRUE(getObject->Has(ecmaVm, tmpStr)); + Local result = getObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsArray(ecmaVm)); + + auto internalDescripties = std::vector>(); + std::unique_ptr internalPropertyDescriptor = + std::make_unique(); + internalPropertyDescriptor->SetName("filename1"); + internalDescripties.emplace_back(std::move(internalPropertyDescriptor)); + ASSERT_EQ(internalDescripties.back()->GetName(), "filename1"); + + auto privateProperties = std::vector>(); + std::unique_ptr privatePropertyDescriptor = + std::make_unique(); + privatePropertyDescriptor->SetName("filename2"); + privateProperties.emplace_back(std::move(privatePropertyDescriptor)); + ASSERT_EQ(privateProperties.back()->GetName(), "filename2"); +} + +HWTEST_F_L0(DebuggerReturnsTest, StopSamplingReturnsToObjectTest) +{ + std::unique_ptr head = std::make_unique(); + std::unique_ptr profile = std::make_unique(); + profile->SetHead(std::move(head)); + profile->SetSamples(); + std::unique_ptr stopSamplingReturns = + std::make_unique(std::move(profile)); + ASSERT_NE(stopSamplingReturns, nullptr); + Local object = stopSamplingReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "profile"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + Local result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); +} + +HWTEST_F_L0(DebuggerReturnsTest, GetHeapObjectIdReturnsToObjectTest) +{ + std::unique_ptr getHeapObjectIdReturns = std::make_unique(10); + ASSERT_NE(getHeapObjectIdReturns, nullptr); + + Local object = getHeapObjectIdReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "heapSnapshotObjectId"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + + Local result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(std::string("10"), Local(result)->ToString()); +} + +HWTEST_F_L0(DebuggerReturnsTest, GetObjectByHeapObjectIdReturnsToObjectTest) +{ + std::unique_ptr remoteObjectResult = std::make_unique(); + std::unique_ptr getObjectByHeapObjectIdReturns = + std::make_unique(std::move(remoteObjectResult)); + ASSERT_NE(getObjectByHeapObjectIdReturns, nullptr); + + Local object = getObjectByHeapObjectIdReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "result"); + ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); + + Local result = object->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_EQ(std::move(remoteObjectResult), nullptr); +} + +HWTEST_F_L0(DebuggerReturnsTest, StopReturnsToObjectTest) +{ + std::unique_ptr profile = std::make_unique(); + std::unique_ptr stopReturns= std::make_unique(std::move(profile)); + ASSERT_NE(stopReturns, nullptr); + Local temp = stopReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "profile"); + ASSERT_TRUE(temp->Has(ecmaVm, tmpStr)); + Local result = temp->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); +} + +HWTEST_F_L0(DebuggerReturnsTest, GetHeapUsageReturnsToObjectTest) +{ + double usedSize = 1; + double totalSize = 1; + std::unique_ptr getHeapUsageReturns = + std::make_unique(usedSize, totalSize); + ASSERT_NE(getHeapUsageReturns, nullptr); + Local getObject = getHeapUsageReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "usedSize"); + ASSERT_TRUE(getObject->Has(ecmaVm, tmpStr)); + Local result = getObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->Value(), 1); + + tmpStr = StringRef::NewFromUtf8(ecmaVm, "totalSize"); + ASSERT_TRUE(getObject->Has(ecmaVm, tmpStr)); + result = getObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->Value(), 1); +} + +HWTEST_F_L0(DebuggerReturnsTest, GetBestEffortCoverageReturnsToObjectTest) +{ + auto result = std::vector>(); + std::unique_ptr scriptCoverage = std::make_unique(); + std::unique_ptr getBestEffortCoverageReturns = + std::make_unique(std::move(result)); + Local getObject = getBestEffortCoverageReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "result"); + ASSERT_TRUE(getObject->Has(ecmaVm, tmpStr)); + Local tmpResult = getObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!tmpResult.IsEmpty() && !tmpResult->IsUndefined()); + ASSERT_TRUE(tmpResult->IsArray(ecmaVm)); +} + +HWTEST_F_L0(DebuggerReturnsTest, StartPreciseCoverageReturnsToObjectTest) +{ + std::unique_ptr startPreciseCoverageReturns + = std::make_unique(1001); + ASSERT_NE(startPreciseCoverageReturns, nullptr); + Local getObject = startPreciseCoverageReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "timestamp"); + ASSERT_TRUE(getObject->Has(ecmaVm, tmpStr)); + Local result = getObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + EXPECT_EQ(Local(result)->Value(), 1001); +} + +HWTEST_F_L0(DebuggerReturnsTest, TakePreciseCoverageReturnsToObjectTest) +{ + auto coverage = std::vector>(); + std::unique_ptr takePreciseCoverageReturns = + std::make_unique(std::move(coverage), 1001); + ASSERT_NE(takePreciseCoverageReturns, nullptr); + Local getObject = takePreciseCoverageReturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "result"); + ASSERT_TRUE(getObject->Has(ecmaVm, tmpStr)); + Local result = getObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); + ASSERT_TRUE(result->IsArray(ecmaVm)); + + Local instrumentationObject = takePreciseCoverageReturns->ToObject(ecmaVm); + Local tmperStr = StringRef::NewFromUtf8(ecmaVm, "timestamp"); + ASSERT_TRUE(instrumentationObject->Has(ecmaVm, tmperStr)); + Local tmpResult = instrumentationObject->Get(ecmaVm, tmperStr); + ASSERT_TRUE(!tmpResult.IsEmpty() && !tmpResult->IsUndefined()); + EXPECT_EQ(Local(tmpResult)->Value(), 1001); +} + +HWTEST_F_L0(DebuggerReturnsTest, TakeTypeProfileturnsToObjectTest) +{ + auto result = std::vector>(); + std::unique_ptr scriptTypeProfile = std::make_unique(); + std::unique_ptr takeTypeProfileturns = std::make_unique + (std::move(result)); + Local getObject = takeTypeProfileturns->ToObject(ecmaVm); + Local tmpStr = StringRef::NewFromUtf8(ecmaVm, "result"); + ASSERT_TRUE(getObject->Has(ecmaVm, tmpStr)); + Local tmpResult = getObject->Get(ecmaVm, tmpStr); + ASSERT_TRUE(!tmpResult.IsEmpty() && !tmpResult->IsUndefined()); + ASSERT_TRUE(tmpResult->IsArray(ecmaVm)); +} +#endif +} // namespace panda::test \ No newline at end of file diff --git a/ecmascript/tooling/test/debugger_script_test.cpp b/ecmascript/tooling/test/debugger_script_test.cpp index b392e5bbeec814a65f4d17c1a9c0cb7ae42b390a..5d3df5e711be1987f6fbba3e3d236944de8a6840 100644 --- a/ecmascript/tooling/test/debugger_script_test.cpp +++ b/ecmascript/tooling/test/debugger_script_test.cpp @@ -21,12 +21,11 @@ #include "ecmascript/tooling/base/pt_returns.h" #include "ecmascript/tooling/debugger_service.h" #include "ecmascript/tooling/dispatcher.h" -#include "ecmascript/tooling/interface/js_debugger.h" +#include "ecmascript/tooling/backend/js_debugger.h" #include "ecmascript/tooling/base/pt_script.h" using namespace panda::ecmascript; using namespace panda::ecmascript::tooling; -using namespace panda::tooling; namespace panda::test { class DebuggerScriptTest : public testing::Test { @@ -62,8 +61,8 @@ protected: HWTEST_F_L0(DebuggerScriptTest, ScriptIdTest) { std::unique_ptr script = std::make_unique(1, "name_1", "url_1", "source_1"); - script->SetScriptId("id_100"); - ASSERT_EQ(script->GetScriptId(), "id_100"); + script->SetScriptId(100); + ASSERT_EQ(script->GetScriptId(), 100); } HWTEST_F_L0(DebuggerScriptTest, FileNameTest) diff --git a/ecmascript/tooling/test/debugger_types_test.cpp b/ecmascript/tooling/test/debugger_types_test.cpp index 83ef7b8b8279c63a8b0970575807423af2581162..50d277f1eca8dc08b1b89f79f5115c8babc26eb2 100644 --- a/ecmascript/tooling/test/debugger_types_test.cpp +++ b/ecmascript/tooling/test/debugger_types_test.cpp @@ -57,7 +57,7 @@ public: void TearDown() override { - TestHelper::DestroyEcmaVMWithScope(instance, scope); + TestHelper::DestroyEcmaVMWithScope(ecmaVm, scope); } protected: @@ -69,309 +69,288 @@ protected: HWTEST_F_L0(DebuggerTypesTest, RemoteObjectCreateTest) { - CString msg; + std::string msg; std::unique_ptr remoteObject; - Local tmpStr; // abnormal params of null msg - msg = CString() + R"({})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of params.sub-key = [ type = 100, ] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":100}})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of params.sub-key = [ type = [ "sub": "test" ] }, ] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":100}})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // normal params of params.sub-key = [ type = "object", ] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"("}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"("}})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); // abnormal params of params.sub-key = [ type = "object", subtype = "unknown"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","subtype":"unknown"}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of params.sub-key = [ type = "object", subtype = 100] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","subtype":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // normal params of params.sub-key = [ type = "object", subtype = "array"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Array + R"("}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); ASSERT_TRUE(remoteObject->HasSubType()); EXPECT_EQ(ObjectSubType::Array, remoteObject->GetSubType()); // abnormal params of params.sub-key = [ type = "object", className = 100] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","className":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of params.sub-key = [ type = "object", className = {"xx":"yy"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","className":{"xx":"yy"}}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // normal params of params.sub-key = [ type = "object", className = "TestClass"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","className":"TestClass"}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); ASSERT_TRUE(remoteObject->HasClassName()); EXPECT_EQ("TestClass", remoteObject->GetClassName()); // normal params of params.sub-key = [ type = "object", value = 100] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","value":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); - ASSERT_TRUE(remoteObject->HasValue()); - EXPECT_EQ(Local(remoteObject->GetValue())->Value(), 100.0); // normal params of params.sub-key = [ type = "object", value = {"xx":"yy"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","value":{"xx":"yy"}}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); - ASSERT_TRUE(remoteObject->HasValue()); - ASSERT_TRUE(remoteObject->GetValue()->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "xx"); - ASSERT_TRUE(Local(remoteObject->GetValue())->Has(ecmaVm, Local(tmpStr))); // normal params of params.sub-key = [ type = "object", value = "Test"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","value":"Test"}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); - ASSERT_TRUE(remoteObject->HasValue()); - EXPECT_EQ("Test", Local(remoteObject->GetValue())->ToString()); // abnormal params of params.sub-key = [ type = "object", unserializableValue = 100] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","unserializableValue":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of params.sub-key = [ type = "object", unserializableValue = {"xx":"yy"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","unserializableValue":{"xx":"yy"}}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // normal params of params.sub-key = [ type = "object", unserializableValue = "TestClass"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","unserializableValue":"Test"}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); ASSERT_TRUE(remoteObject->HasUnserializableValue()); EXPECT_EQ("Test", remoteObject->GetUnserializableValue()); // abnormal params of params.sub-key = [ type = "object", description = 100] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","description":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of params.sub-key = [ type = "object", description = {"xx":"yy"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","description":{"xx":"yy"}}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // normal params of params.sub-key = [ type = "object", description = "Test"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","description":"Test"}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); ASSERT_TRUE(remoteObject->HasDescription()); EXPECT_EQ("Test", remoteObject->GetDescription()); // abnormal params of params.sub-key = [ type = "object", objectId = 100] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","objectId":100}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // abnormal params of params.sub-key = [ type = "object", objectId = {"xx":"yy"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","objectId":{"xx":"yy"}}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(remoteObject, nullptr); // normal params of params.sub-key = [ type = "object", objectId = "id_1"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + - R"(","objectId":"id_1"}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + R"(","objectId":"1"}})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); EXPECT_EQ(ObjectType::Object, remoteObject->GetType()); ASSERT_TRUE(remoteObject->HasObjectId()); - EXPECT_EQ("id_1", remoteObject->GetObjectId()); + EXPECT_EQ(remoteObject->GetObjectId(), 1); } -HWTEST_F_L0(DebuggerTypesTest, RemoteObjectToObjectTest) +HWTEST_F_L0(DebuggerTypesTest, RemoteObjectToJsonTest) { - CString msg; + std::string msg; std::unique_ptr remoteObject; - Local tmpStr; + std::string tmpStr; + Result ret; - msg = - CString() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + R"(","subtype":")" + - ObjectSubType::Array + - R"(","className":"TestClass","value":100,"unserializableValue":"Test","description":"Test","objectId":"id_1"}})"; - remoteObject = RemoteObject::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"type":")" + ObjectType::Object + + R"(", "subtype":")" + ObjectSubType::Array + + R"(","className":"TestClass","value":100, "unserializableValue":"Test","description":"Test","objectId":"1"}})"; + remoteObject = RemoteObject::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(remoteObject, nullptr); - Local object = remoteObject->ToObject(ecmaVm); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - Local result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Array.c_str()), Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "className"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("TestClass", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "value"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 100.0); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "unserializableValue"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("Test", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "description"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("Test", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "objectId"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("id_1", Local(result)->ToString()); + auto objJson = remoteObject->ToJson(); + + ret = objJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + + ret = objJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Array.c_str()), tmpStr); + + ret = objJson->GetString("className", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("TestClass", tmpStr); + + ret = objJson->GetString("unserializableValue", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("Test", tmpStr); + + ret = objJson->GetString("description", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("Test", tmpStr); + + ret = objJson->GetString("objectId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("1", tmpStr); } HWTEST_F_L0(DebuggerTypesTest, ExceptionDetailsCreateTest) { - CString msg; + std::string msg; std::unique_ptr exceptionMetaData; // abnormal params of null msg - msg = CString() + R"({})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({})"; + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = [ exceptionId="Test","text"="text0","lineNumber"=10,"columnNumber"=20] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":"Test","text":"text0","lineNumber":10,"columnNumber":20}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = [ exceptionId={"xx":"yy"},"text"="text0","lineNumber"=10,"columnNumber"=20] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":{"xx":"yy"},"text":"text0","lineNumber":10,"columnNumber":20}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = [ exceptionId=3,"text"=10,"lineNumber"=10,"columnNumber"=20] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":10,"lineNumber":10,"columnNumber":20}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = [ exceptionId=3,"text"=["text0"],"lineNumber"=10,"columnNumber"=20] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":["text0"],"lineNumber":10,"columnNumber":20}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = [ exceptionId=3,"text"="text0","lineNumber"="10","columnNumber"=20] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":"10","columnNumber":20}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = [ exceptionId=3,"text"="text0","lineNumber"=["10"],"columnNumber"=20] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":["10"],"columnNumber":20}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = [ exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"="20"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":"20"}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = [ exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=["20"]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":["20"]}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // normal params of params.sub-key = [ exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(exceptionMetaData, nullptr); EXPECT_EQ(exceptionMetaData->GetExceptionId(), 3); EXPECT_EQ("text0", exceptionMetaData->GetText()); @@ -380,49 +359,49 @@ HWTEST_F_L0(DebuggerTypesTest, ExceptionDetailsCreateTest) // abnormal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"scriptId"=10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"scriptId":10}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"scriptId"=["10"]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"scriptId":["10"]}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // normal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"scriptId"="id0"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"scriptId":"id0"}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"scriptId":"0"}})"; + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(exceptionMetaData, nullptr); EXPECT_EQ(exceptionMetaData->GetExceptionId(), 3); EXPECT_EQ("text0", exceptionMetaData->GetText()); EXPECT_EQ(exceptionMetaData->GetLine(), 10); EXPECT_EQ(exceptionMetaData->GetColumn(), 20); - EXPECT_EQ("id0", exceptionMetaData->GetScriptId()); + EXPECT_EQ(exceptionMetaData->GetScriptId(), 0); // abnormal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"url"=10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"url":10}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"url"=["10"]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"url":["10"]}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // normal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"url"="url0"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"url":"url0"}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(exceptionMetaData, nullptr); EXPECT_EQ(exceptionMetaData->GetExceptionId(), 3); EXPECT_EQ("text0", exceptionMetaData->GetText()); @@ -432,24 +411,24 @@ HWTEST_F_L0(DebuggerTypesTest, ExceptionDetailsCreateTest) // abnormal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"exception"=10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"exception":10}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"exception"=["10"]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"exception":["10"]}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // normal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"exception"={}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"exception":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Error + R"("}}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(exceptionMetaData, nullptr); EXPECT_EQ(exceptionMetaData->GetExceptionId(), 3); EXPECT_EQ("text0", exceptionMetaData->GetText()); @@ -462,23 +441,23 @@ HWTEST_F_L0(DebuggerTypesTest, ExceptionDetailsCreateTest) // abnormal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"executionContextId"="10"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"executionContextId":"10"}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // abnormal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"executionContextId"=["10"]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"executionContextId":["10"]}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(exceptionMetaData, nullptr); // normal params of params.sub-key = // [exceptionId=3,"text"="text0","lineNumber"=10,"columnNumber"=20,"executionContextId"=2] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "exceptionId":3,"text":"text0","lineNumber":10,"columnNumber":20,"executionContextId":2}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(exceptionMetaData, nullptr); EXPECT_EQ(exceptionMetaData->GetExceptionId(), 3); EXPECT_EQ("text0", exceptionMetaData->GetText()); @@ -487,152 +466,142 @@ HWTEST_F_L0(DebuggerTypesTest, ExceptionDetailsCreateTest) EXPECT_EQ(exceptionMetaData->GetExecutionContextId(), 2); } -HWTEST_F_L0(DebuggerTypesTest, ExceptionDetailsToObjectTest) +HWTEST_F_L0(DebuggerTypesTest, ExceptionDetailsToJsonTest) { - CString msg; + std::string msg; std::unique_ptr exceptionMetaData; - Local tmpStr; + std::string tmpStr; + int32_t tmpInt; + std::unique_ptr tmpJson; + Result ret; - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "exceptionId":5,"text":"text0","lineNumber":10,"columnNumber":20,"scriptId":"ScriptId0","url":"url0", + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "exceptionId":5,"text":"text0","lineNumber":10,"columnNumber":20,"scriptId":"100","url":"url0", "exception":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Error + R"("},"executionContextId":30}})"; - exceptionMetaData = ExceptionDetails::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + exceptionMetaData = ExceptionDetails::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(exceptionMetaData, nullptr); - Local object = exceptionMetaData->ToObject(ecmaVm); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "exceptionId"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - Local result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 5); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "text"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("text0", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "lineNumber"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 10); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "columnNumber"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 20); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptId"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("ScriptId0", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "url"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("url0", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "exception"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - Local subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Error.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "executionContextId"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 30); + auto objJson = exceptionMetaData->ToJson(); + + ret = objJson->GetInt("exceptionId", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 5); + + ret = objJson->GetString("text", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("text0", tmpStr); + + ret = objJson->GetInt("lineNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 10); + + ret = objJson->GetInt("columnNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 20); + + ret = objJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("100", tmpStr); + + ret = objJson->GetString("url", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("url0", tmpStr); + + ret = objJson->GetObject("exception", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Error.c_str()), tmpStr); + + ret = objJson->GetInt("executionContextId", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 30); } HWTEST_F_L0(DebuggerTypesTest, InternalPropertyDescriptorCreateTest) { - CString msg; + std::string msg; std::unique_ptr internalPropertyDescriptor; // abnormal params of null msg - msg = CString() + R"({})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({})"; + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of unknown params.sub-key=["name":"name8"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":99}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of unknown params.sub-key=["name":"name8"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":99}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of unknown params.sub-key=["name":"name8","value":99] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":99}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of unknown params.sub-key=["name":99] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":99}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of unknown params.sub-key=["name":[99]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":[99]}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name7"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name7"}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(internalPropertyDescriptor, nullptr); EXPECT_EQ("name7", internalPropertyDescriptor->GetName()); // abnormal params of unknown params.sub-key=["name":"name8","value":{"type":"object","subtype":"map"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":"99"}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // abnormal params of unknown params.sub-key=["name":"name8","value":{"type":"object","subtype":"wrong"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":{"type":")" + ObjectType::Object + R"(","subtype":"wrong"}}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(internalPropertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name8","value":{"type":"object","subtype":"map"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Map + R"("}}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(internalPropertyDescriptor, nullptr); EXPECT_EQ("name8", internalPropertyDescriptor->GetName()); ASSERT_TRUE(internalPropertyDescriptor->HasValue()); @@ -642,119 +611,114 @@ HWTEST_F_L0(DebuggerTypesTest, InternalPropertyDescriptorCreateTest) EXPECT_EQ(value->GetSubType(), ObjectSubType::Map); } -HWTEST_F_L0(DebuggerTypesTest, InternalPropertyDescriptorToObjectTest) +HWTEST_F_L0(DebuggerTypesTest, InternalPropertyDescriptorToJsonTest) { - CString msg; + std::string msg; std::unique_ptr internalPropertyDescriptor; - Local tmpStr; + std::string tmpStr; + std::unique_ptr tmpJson; + Result ret; - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Map + R"("}}})"; - internalPropertyDescriptor = InternalPropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + internalPropertyDescriptor = InternalPropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(internalPropertyDescriptor, nullptr); - Local object = internalPropertyDescriptor->ToObject(ecmaVm); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "name"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - Local result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("name8", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "value"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - Local subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Map.c_str()), Local(subResult)->ToString()); + auto objJson = internalPropertyDescriptor->ToJson(); + + ret = objJson->GetString("name", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("name8", tmpStr); + + ret = objJson->GetObject("value", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Map.c_str()), tmpStr); } HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorCreateTest) { - CString msg; + std::string msg; std::unique_ptr propertyDescriptor; // abnormal params of null msg - msg = CString() + R"({})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({})"; + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":10,"configurable":true,"enumerable":true] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":10,"configurable":true,"enumerable":true,"value":10}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":["name85"],"configurable":true,"enumerable":true] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":["name85"],"configurable":true,"enumerable":true,"value":10}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":10,"enumerable":true] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":10,"enumerable":true}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":"true","enumerable":true] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":"true","enumerable":true}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":10}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":"true"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":"true"}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"value":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"value":10}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"value":{"ee":"11"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"value":{"ee":"11"}}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"value":{..}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"value":{"type":")" + ObjectType::Symbol + R"("}}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(propertyDescriptor, nullptr); EXPECT_EQ("name85", propertyDescriptor->GetName()); ASSERT_TRUE(propertyDescriptor->GetConfigurable()); @@ -764,21 +728,21 @@ HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorCreateTest) EXPECT_EQ(value->GetType(), ObjectType::Symbol); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"writable":98] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"writable":98}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"writable":[true]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"writable":[true]}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"writable":true] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"writable":true}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(propertyDescriptor, nullptr); EXPECT_EQ("name85", propertyDescriptor->GetName()); ASSERT_TRUE(propertyDescriptor->GetConfigurable()); @@ -786,22 +750,22 @@ HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorCreateTest) ASSERT_TRUE(propertyDescriptor->GetWritable()); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"get":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"get":10}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"get":[10]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"get":[10]}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"get":{}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"get":{"type":")" + ObjectType::Function + R"("}}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(propertyDescriptor, nullptr); EXPECT_EQ("name85", propertyDescriptor->GetName()); ASSERT_TRUE(propertyDescriptor->GetConfigurable()); @@ -811,22 +775,22 @@ HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorCreateTest) EXPECT_EQ(get->GetType(), ObjectType::Function); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"set":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"set":10}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"set":[10]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"set":[10]}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"set":{}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"set":{"type":")" + ObjectType::String + R"("}}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(propertyDescriptor, nullptr); EXPECT_EQ("name85", propertyDescriptor->GetName()); ASSERT_TRUE(propertyDescriptor->GetConfigurable()); @@ -836,21 +800,21 @@ HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorCreateTest) EXPECT_EQ(set->GetType(), ObjectType::String); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"wasThrown":98] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"wasThrown":98}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"wasThrown":[true]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"wasThrown":[true]}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"wasThrown":true] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"wasThrown":true}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(propertyDescriptor, nullptr); EXPECT_EQ("name85", propertyDescriptor->GetName()); ASSERT_TRUE(propertyDescriptor->GetConfigurable()); @@ -858,21 +822,21 @@ HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorCreateTest) ASSERT_TRUE(propertyDescriptor->GetWasThrown()); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"isOwn":98] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"isOwn":98}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"isOwn":[true]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"isOwn":[true]}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true,"isOwn":true] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"isOwn":true}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(propertyDescriptor, nullptr); EXPECT_EQ("name85", propertyDescriptor->GetName()); ASSERT_TRUE(propertyDescriptor->GetConfigurable()); @@ -880,22 +844,22 @@ HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorCreateTest) ASSERT_TRUE(propertyDescriptor->GetIsOwn()); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true, "symbol":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"symbol":10}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // abnormal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true, "symbol":[10]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"symbol":[10]}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(propertyDescriptor, nullptr); // normal params of params.sub-key=["name":"name8","configurable":true,"enumerable":true, "symbol":{}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name85","configurable":true,"enumerable":true,"symbol":{"type":")" + ObjectType::Wasm + R"("}}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(propertyDescriptor, nullptr); EXPECT_EQ("name85", propertyDescriptor->GetName()); ASSERT_TRUE(propertyDescriptor->GetConfigurable()); @@ -905,13 +869,16 @@ HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorCreateTest) EXPECT_EQ(symbol->GetType(), ObjectType::Wasm); } -HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorToObjectTest) +HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorToJsonTest) { - CString msg; + std::string msg; std::unique_ptr propertyDescriptor; - Local tmpStr; + std::string tmpStr; + std::unique_ptr tmpJson; + bool tmpBool; + Result ret; - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "name":"name8","value":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Map + R"("}, "writable":true,"get":{"type":")" + @@ -919,449 +886,410 @@ HWTEST_F_L0(DebuggerTypesTest, PropertyDescriptorToObjectTest) ObjectType::Object + R"(","subtype":")" + ObjectSubType::Generator + R"("},"configurable":true,"enumerable":true,"wasThrown":true,"isOwn":true,"symbol":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Proxy + R"("}}})"; - propertyDescriptor = PropertyDescriptor::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + propertyDescriptor = PropertyDescriptor::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(propertyDescriptor, nullptr); - Local object = propertyDescriptor->ToObject(ecmaVm); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "name"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - Local result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("name8", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "value"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - Local subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Map.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "writable"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsTrue()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "get"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Regexp.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "set"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Generator.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "configurable"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsTrue()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "enumerable"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsTrue()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "wasThrown"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsTrue()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "isOwn"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsTrue()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "symbol"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Proxy.c_str()), Local(subResult)->ToString()); + auto objJson = propertyDescriptor->ToJson(); + + ret = objJson->GetString("name", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("name8", tmpStr); + + ret = objJson->GetObject("value", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Map.c_str()), tmpStr); + + ret = objJson->GetBool("writable", &tmpBool); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_TRUE(tmpBool); + + ret = objJson->GetObject("get", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Regexp.c_str()), tmpStr); + + ret = objJson->GetObject("set", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Generator.c_str()), tmpStr); + + ret = objJson->GetBool("configurable", &tmpBool); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_TRUE(tmpBool); + + ret = objJson->GetBool("enumerable", &tmpBool); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_TRUE(tmpBool); + + ret = objJson->GetBool("wasThrown", &tmpBool); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_TRUE(tmpBool); + + ret = objJson->GetBool("isOwn", &tmpBool); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_TRUE(tmpBool); + + ret = objJson->GetObject("symbol", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Proxy.c_str()), tmpStr); } HWTEST_F_L0(DebuggerTypesTest, LocationCreateTest) { - CString msg; + std::string msg; std::unique_ptr location; // abnormal params of null msg - msg = CString() + R"({})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({})"; + location = Location::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(location, nullptr); // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + location = Location::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(location, nullptr); // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + location = Location::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(location, nullptr); // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + location = Location::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(location, nullptr); // abnormal params of params.sub-key=["scriptId":10,"lineNumber":99] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "scriptId":10,"lineNumber":99 }})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + location = Location::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(location, nullptr); // abnormal params of params.sub-key=["scriptId":["id3"],"lineNumber":99] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "scriptId":["id3"],"lineNumber":99 }})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + location = Location::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(location, nullptr); - // abnormal params of params.sub-key=["scriptId":"id222","lineNumber":"99"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":"99" + // abnormal params of params.sub-key=["scriptId":"222","lineNumber":"99"] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":"99" }})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + location = Location::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(location, nullptr); - // abnormal params of params.sub-key=["scriptId":"id222","lineNumber":[99]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":[99] + // abnormal params of params.sub-key=["scriptId":"222","lineNumber":[99]] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":[99] }})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + location = Location::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(location, nullptr); - // abnormal params of params.sub-key=["scriptId":"id2","lineNumber":99,"columnNumber":"18"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":899,"columnNumber":"18" + // normal params of params.sub-key=["scriptId":"2","lineNumber":99,"columnNumber":138] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":899,"columnNumber":138 }})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); - EXPECT_EQ(location, nullptr); - - // normal params of params.sub-key=["scriptId":"id2","lineNumber":99,"columnNumber":138] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":899,"columnNumber":138 - }})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + location = Location::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(location, nullptr); - EXPECT_EQ("id222", location->GetScriptId()); + EXPECT_EQ(location->GetScriptId(), 222); EXPECT_EQ(location->GetLine(), 899); EXPECT_EQ(location->GetColumn(), 138); - // normal params of params.sub-key=["scriptId":"id2122","lineNumber":8299] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id2122","lineNumber":8299 + // normal params of params.sub-key=["scriptId":"2122","lineNumber":8299] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"2122","lineNumber":8299 }})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + location = Location::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(location, nullptr); - EXPECT_EQ("id2122", location->GetScriptId()); + EXPECT_EQ(location->GetScriptId(), 2122); EXPECT_EQ(location->GetLine(), 8299); } -HWTEST_F_L0(DebuggerTypesTest, LocationToObjectTest) +HWTEST_F_L0(DebuggerTypesTest, LocationToJsonTest) { - CString msg; + std::string msg; std::unique_ptr location; - Local tmpStr; + std::string tmpStr; + int32_t tmpInt; + Result ret; - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id2","lineNumber":99,"columnNumber":18 + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"2","lineNumber":99,"columnNumber":18 }})"; - location = Location::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + location = Location::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(location, nullptr); - Local object = location->ToObject(ecmaVm); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptId"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - Local result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("id2", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "lineNumber"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 99); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "columnNumber"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 18); + auto objJson = location->ToJson(); + + ret = objJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("2", tmpStr); + + ret = objJson->GetInt("lineNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 99); + + ret = objJson->GetInt("columnNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 18); } HWTEST_F_L0(DebuggerTypesTest, BreakLocationCreateTest) { - CString msg; + std::string msg; std::unique_ptr breakLocation; // abnormal params of null msg - msg = CString() + R"({})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({})"; + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); // abnormal params of params.sub-key=["scriptId":10,"lineNumber":99] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "scriptId":10,"lineNumber":99 }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); // abnormal params of params.sub-key=["scriptId":["id3"],"lineNumber":99] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "scriptId":["id3"],"lineNumber":99 }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); - // abnormal params of params.sub-key=["scriptId":"id222","lineNumber":"99"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":"99" + // abnormal params of params.sub-key=["scriptId":"222","lineNumber":"99"] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":"99" }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); - // abnormal params of params.sub-key=["scriptId":"id222","lineNumber":[99]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":[99] + // abnormal params of params.sub-key=["scriptId":"222","lineNumber":[99]] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":[99] }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); - // abnormal params of params.sub-key=["scriptId":"id2","lineNumber":99,"columnNumber":"18"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":899,"columnNumber":"18" + // abnormal params of params.sub-key=["scriptId":"2","lineNumber":99,"columnNumber":"18"] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":899,"columnNumber":"18" }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); - // abnormal params of params.sub-key=["scriptId":"id2","lineNumber":99,"columnNumber":"18","type":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":899,"columnNumber":"18","type":10 + // abnormal params of params.sub-key=["scriptId":"2","lineNumber":99,"columnNumber":"18","type":10] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":899,"columnNumber":"18","type":10 }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); - // abnormal params of params.sub-key=["scriptId":"id2","lineNumber":99,"columnNumber":"18","type":"ee"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":899,"columnNumber":"18","type":"ee" + // abnormal params of params.sub-key=["scriptId":"2","lineNumber":99,"columnNumber":"18","type":"ee"] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":899,"columnNumber":"18","type":"ee" }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(breakLocation, nullptr); - // normal params of params.sub-key=["scriptId":"id2","lineNumber":99,"columnNumber":138,"type":"return"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id222","lineNumber":899,"columnNumber":138,"type":"return" + // normal params of params.sub-key=["scriptId":"2","lineNumber":99,"columnNumber":138,"type":"return"] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"222","lineNumber":899,"columnNumber":138,"type":"return" }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(breakLocation, nullptr); - EXPECT_EQ("id222", breakLocation->GetScriptId()); + EXPECT_EQ(breakLocation->GetScriptId(), 222); EXPECT_EQ(breakLocation->GetLine(), 899); EXPECT_EQ(breakLocation->GetColumn(), 138); EXPECT_EQ("return", breakLocation->GetType()); - // normal params of params.sub-key=["scriptId":"id2122","lineNumber":8299] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id2122","lineNumber":8299 + // normal params of params.sub-key=["scriptId":"2122","lineNumber":8299] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"2122","lineNumber":8299 }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(breakLocation, nullptr); - EXPECT_EQ("id2122", breakLocation->GetScriptId()); + EXPECT_EQ(breakLocation->GetScriptId(), 2122); EXPECT_EQ(breakLocation->GetLine(), 8299); } -HWTEST_F_L0(DebuggerTypesTest, BreakLocationToObjectTest) +HWTEST_F_L0(DebuggerTypesTest, BreakLocationToJsonTest) { - CString msg; + std::string msg; std::unique_ptr breakLocation; - Local tmpStr; + std::string tmpStr; + int32_t tmpInt; + Result ret; - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "scriptId":"id12","lineNumber":919,"columnNumber":148,"type":"call" + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"12","lineNumber":919,"columnNumber":148,"type":"call" }})"; - breakLocation = BreakLocation::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + breakLocation = BreakLocation::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(breakLocation, nullptr); - Local object = breakLocation->ToObject(ecmaVm); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptId"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - Local result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("id12", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "lineNumber"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 919); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "columnNumber"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ(Local(result)->Value(), 148); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("call", Local(result)->ToString()); + auto objJson = breakLocation->ToJson(); + + ret = objJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("12", tmpStr); + + ret = objJson->GetInt("lineNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 919); + + ret = objJson->GetInt("columnNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 148); + + ret = objJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("call", tmpStr); } HWTEST_F_L0(DebuggerTypesTest, ScopeCreateTest) { - CString msg; + std::string msg; std::unique_ptr scope; // abnormal params of null msg - msg = CString() + R"({})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({})"; + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":"ss","object":{..}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"ss","object":{"type":")" + ObjectType::Bigint + R"("}}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":12,"object":{..}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":12,"object":{"type":")" + ObjectType::Bigint + R"("}}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":"global","object":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":10}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":"global","object":{..}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"ww":")" + ObjectType::Bigint + R"("}}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":"global","object":{..},"name":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Bigint + R"("},"name":10}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":"global","object":{..},"name":["10"]] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Bigint + R"("},"name":["10"]}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // normal params of params.sub-key=["type":"global","object":{..},"name":"name128"] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Bigint + R"("},"name":"name117"}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(scope, nullptr); EXPECT_EQ("name117", scope->GetName()); // abnormal params of params.sub-key=["type":"global","object":{..},"startLocation":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Bigint + R"("},"startLocation":10}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":"global","object":{..},"startLocation":{"12":"34"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Bigint + R"("},"startLocation":{"12":"34"}}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":"global","object":{..},"endLocation":10] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Bigint + R"("},"endLocation":10}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // abnormal params of params.sub-key=["type":"global","object":{..},"endLocation":{"12":"34"}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Bigint + R"("},"endLocation":{"12":"34"}}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(scope, nullptr); // normal params of params.sub-key=["type":"global","object":{..}] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Bigint + R"("}}})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(scope, nullptr); EXPECT_EQ("global", scope->GetType()); RemoteObject *object = scope->GetObject(); @@ -1369,282 +1297,267 @@ HWTEST_F_L0(DebuggerTypesTest, ScopeCreateTest) EXPECT_EQ(object->GetType(), ObjectType::Bigint); } -HWTEST_F_L0(DebuggerTypesTest, ScopeToObjectTest) +HWTEST_F_L0(DebuggerTypesTest, ScopeToJsonTest) { - CString msg; + std::string msg; std::unique_ptr scope; - Local tmpStr; + std::string tmpStr; + int32_t tmpInt; + std::unique_ptr tmpJson; + Result ret; - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "type":"global","object":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Dataview + R"("},"name":"name9", - "startLocation":{"scriptId":"id2","lineNumber":99}, - "endLocation":{"scriptId":"id13","lineNumber":146} + "startLocation":{"scriptId":"2","lineNumber":99}, + "endLocation":{"scriptId":"13","lineNumber":146} }})"; - scope = Scope::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + scope = Scope::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(scope, nullptr); - Local object = scope->ToObject(ecmaVm); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - Local result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("global", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "object"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - Local subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Dataview.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "name"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("name9", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "startLocation"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptId"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ("id2", Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "lineNumber"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(Local(subResult)->Value(), 99); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "endLocation"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptId"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ("id13", Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "lineNumber"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(Local(subResult)->Value(), 146); + auto objJson = scope->ToJson(); + + ret = objJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("global", tmpStr); + + ret = objJson->GetObject("object", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Dataview.c_str()), tmpStr); + + ret = objJson->GetString("name", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("name9", tmpStr); + + ret = objJson->GetObject("startLocation", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("2", tmpStr); + ret = tmpJson->GetInt("lineNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 99); + + ret = objJson->GetObject("endLocation", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("13", tmpStr); + ret = tmpJson->GetInt("lineNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 146); } HWTEST_F_L0(DebuggerTypesTest, CallFrameCreateTest) { - CString msg; + std::string msg; std::unique_ptr callFrame; // abnormal params of null msg - msg = CString() + R"({})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({})"; + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of unexist key params - msg = CString() + R"({"id":0,"method":"Debugger.Test"})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of null params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of unknown params.sub-key - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ "callFrameId":10,"functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":["id0"],"functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":["0"],"functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":10, - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":10, + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":["name0"], - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":["name0"], + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0","functionLocation":10, - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0","functionLocation":10, + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0","functionLocation":{"scriptId11":"id5","lineNumber":19}, - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0","functionLocation":{"scriptId11":"id5","lineNumber":19}, + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", "location":{"scriptId2":"id5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", "location":10,"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":10,"scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":10,"scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":{"url":"url7"},"scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":{"url":"url7"},"scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", "location":{"scriptId":"id5","lineNumber":19}, + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", "location":{"scriptId":"5","lineNumber":19}, "url":"url7","scopeChain":10,"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": {"type":"22","object":{"type":")" + ObjectType::Object + R"("}},"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":10}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"11":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}, "returnValue":10}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // abnormal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}, "returnValue":{"type":"object","subtype":"11"}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); EXPECT_EQ(callFrame, nullptr); // normal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0", - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0", + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(callFrame, nullptr); - EXPECT_EQ("id0", callFrame->GetCallFrameId()); + EXPECT_EQ(callFrame->GetCallFrameId(), 0); EXPECT_EQ("name0", callFrame->GetFunctionName()); ASSERT_FALSE(callFrame->HasFunctionLocation()); Location *location = callFrame->GetLocation(); - EXPECT_EQ("id5", location->GetScriptId()); + EXPECT_EQ(location->GetScriptId(), 5); EXPECT_EQ(location->GetLine(), 19); EXPECT_EQ("url7", callFrame->GetUrl()); - const CVector> *scopeChain = callFrame->GetScopeChain(); - EXPECT_EQ(scopeChain->size(), 2); + const std::vector> *scopeChain = callFrame->GetScopeChain(); + EXPECT_EQ(scopeChain->size(), 2U); RemoteObject *thisObj = callFrame->GetThis(); ASSERT_NE(thisObj, nullptr); EXPECT_EQ(thisObj->GetType(), ObjectType::Object); @@ -1652,26 +1565,26 @@ HWTEST_F_L0(DebuggerTypesTest, CallFrameCreateTest) ASSERT_FALSE(callFrame->HasReturnValue()); // normal params of params.sub-key=[..] - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0","functionLocation":{"scriptId":"id3","lineNumber":16}, - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"10","functionName":"name0","functionLocation":{"scriptId":"3","lineNumber":16}, + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::V128 + R"("},"returnValue":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::I32 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(callFrame, nullptr); - EXPECT_EQ("id0", callFrame->GetCallFrameId()); + EXPECT_EQ(callFrame->GetCallFrameId(), 10); EXPECT_EQ("name0", callFrame->GetFunctionName()); Location *functionLocation = callFrame->GetFunctionLocation(); - EXPECT_EQ("id3", functionLocation->GetScriptId()); + EXPECT_EQ(functionLocation->GetScriptId(), 3); EXPECT_EQ(functionLocation->GetLine(), 16); location = callFrame->GetLocation(); - EXPECT_EQ("id5", location->GetScriptId()); + EXPECT_EQ(location->GetScriptId(), 5); EXPECT_EQ(location->GetLine(), 19); EXPECT_EQ("url7", callFrame->GetUrl()); scopeChain = callFrame->GetScopeChain(); - EXPECT_EQ(scopeChain->size(), 2); + EXPECT_EQ(scopeChain->size(), 2U); thisObj = callFrame->GetThis(); ASSERT_NE(thisObj, nullptr); EXPECT_EQ(thisObj->GetType(), ObjectType::Object); @@ -1682,104 +1595,800 @@ HWTEST_F_L0(DebuggerTypesTest, CallFrameCreateTest) EXPECT_EQ(returnObj->GetSubType(), ObjectSubType::I32); } -HWTEST_F_L0(DebuggerTypesTest, CallFrameToObjectTest) +HWTEST_F_L0(DebuggerTypesTest, CallFrameToJsonTest) { - CString msg; + std::string msg; std::unique_ptr callFrame; - Local tmpStr; - - msg = CString() + R"({"id":0,"method":"Debugger.Test","params":{ - "callFrameId":"id0","functionName":"name0","functionLocation":{"scriptId":"id3","lineNumber":16}, - "location":{"scriptId":"id5","lineNumber":19},"url":"url7","scopeChain": + std::string tmpStr; + int32_t tmpInt; + std::unique_ptr tmpJson; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrameId":"0","functionName":"name0","functionLocation":{"scriptId":"3","lineNumber":16}, + "location":{"scriptId":"5","lineNumber":19},"url":"url7","scopeChain": [{"type":"global","object":{"type":")" + ObjectType::Object + R"("}}, {"type":"local","object":{"type":")" + ObjectType::Object + R"("}}],"this":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::Iterator + R"("},"returnValue":{"type":")" + ObjectType::Object + R"(","subtype":")" + ObjectSubType::I64 + R"("}}})"; - callFrame = CallFrame::Create(ecmaVm, DispatchRequest(ecmaVm, msg).GetParams()); + callFrame = CallFrame::Create(DispatchRequest(msg).GetParams()); ASSERT_NE(callFrame, nullptr); - Local object = callFrame->ToObject(ecmaVm); - - tmpStr = StringRef::NewFromUtf8(ecmaVm, "callFrameId"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - Local result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("id0", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "functionName"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("name0", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "functionLocation"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptId"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - Local subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ("id3", Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "lineNumber"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(Local(subResult)->Value(), 16); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "location"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "scriptId"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ("id5", Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "lineNumber"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(Local(subResult)->Value(), 19); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "url"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - EXPECT_EQ("url7", Local(result)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "scopeChain"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsArray(ecmaVm)); - - EXPECT_EQ(Local(result)->Length(ecmaVm), 2); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "this"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::Iterator.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "returnValue"); - ASSERT_TRUE(object->Has(ecmaVm, tmpStr)); - result = object->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!result.IsEmpty() && !result->IsUndefined()); - ASSERT_TRUE(result->IsObject()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "type"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectType::Object.c_str()), Local(subResult)->ToString()); - tmpStr = StringRef::NewFromUtf8(ecmaVm, "subtype"); - ASSERT_TRUE(Local(result)->Has(ecmaVm, Local(tmpStr))); - subResult = Local(result)->Get(ecmaVm, tmpStr); - ASSERT_TRUE(!subResult.IsEmpty() && !subResult->IsUndefined()); - EXPECT_EQ(std::string(ObjectSubType::I64.c_str()), Local(subResult)->ToString()); + auto objJson = callFrame->ToJson(); + + ret = objJson->GetString("callFrameId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("0", tmpStr); + + ret = objJson->GetString("functionName", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("name0", tmpStr); + + ret = objJson->GetObject("functionLocation", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("3", tmpStr); + ret = tmpJson->GetInt("lineNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 16); + + ret = objJson->GetObject("location", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("5", tmpStr); + ret = tmpJson->GetInt("lineNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 19); + + ret = objJson->GetString("url", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ("url7", tmpStr); + + ret = objJson->GetArray("scopeChain", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + EXPECT_EQ(tmpJson->GetSize(), 2); + + ret = objJson->GetObject("this", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::Iterator.c_str()), tmpStr); + + ret = objJson->GetObject("returnValue", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("type", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectType::Object.c_str()), tmpStr); + ret = tmpJson->GetString("subtype", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(std::string(ObjectSubType::I64.c_str()), tmpStr); +} + +#ifdef SUPPORT_PROFILER_CDP +HWTEST_F_L0(DebuggerTypesTest, SamplingHeapProfileSampleCreateTest) +{ + std::string msg; + std::unique_ptr object; + + // abnormal params of null msg + msg = std::string() + R"({})"; + object = SamplingHeapProfileSample::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + object = SamplingHeapProfileSample::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + object = SamplingHeapProfileSample::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + object = SamplingHeapProfileSample::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of params.sub-key = [ "size"="Test","nodeId"="Test","ordinal"="Test"] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "size":"Test","nodeId":"Test","ordinal":"Test"}})"; + object = SamplingHeapProfileSample::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of params.sub-key = [ "size"={"xx":"yy"},"nodeId"={"xx":"yy"},"ordinal"={"xx":"yy"}] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "size":{"xx":"yy"},"nodeId":{"xx":"yy"},"ordinal":{"xx":"yy"}}})"; + object = SamplingHeapProfileSample::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of params.sub-key = [ "size"=100,"nodeId"=1,"ordinal"=10] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"size":100,"nodeId":1,"ordinal":10}})"; + object = SamplingHeapProfileSample::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(object, nullptr); + EXPECT_EQ(object->GetSize(), 100); + EXPECT_EQ(object->GetNodeId(), 1); + EXPECT_EQ(object->GetOrdinal(), 10); +} + +HWTEST_F_L0(DebuggerTypesTest, SamplingHeapProfileSampleToJsonTest) +{ + std::string msg; + std::unique_ptr samplingHeapProfileSampleData; + std::string tmpStr; + int32_t tmpInt; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"size":100,"nodeId":1,"ordinal":10}})"; + samplingHeapProfileSampleData = + SamplingHeapProfileSample::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(samplingHeapProfileSampleData, nullptr); + auto json = samplingHeapProfileSampleData->ToJson(); + + ret = json->GetInt("size", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 100); + ret = json->GetInt("nodeId", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 1); + ret = json->GetInt("ordinal", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 10); +} + +HWTEST_F_L0(DebuggerTypesTest, SamplingHeapProfileNodeCreateTest) +{ + std::string msg; + std::unique_ptr object; + + // abnormal params of null msg + msg = std::string() + R"({})"; + object = SamplingHeapProfileNode::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + object = SamplingHeapProfileNode::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + object = SamplingHeapProfileNode::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + object = SamplingHeapProfileNode::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrame": {"functionName":"Create", "scriptId":"10", "url":"url3", "lineNumber":100, "columnNumber":20}, + "selfSize":10, + "id":5, + "children":[] + }})"; + object = SamplingHeapProfileNode::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(object, nullptr); + RuntimeCallFrame *runTimeCallFrame = object->GetCallFrame(); + ASSERT_NE(runTimeCallFrame, nullptr); + EXPECT_EQ(runTimeCallFrame->GetFunctionName(), "Create"); + EXPECT_EQ(runTimeCallFrame->GetScriptId(), "10"); + EXPECT_EQ(runTimeCallFrame->GetUrl(), "url3"); + EXPECT_EQ(runTimeCallFrame->GetLineNumber(), 100); + EXPECT_EQ(runTimeCallFrame->GetColumnNumber(), 20); + + EXPECT_EQ(object->GetSelfSize(), 10); + EXPECT_EQ(object->GetId(), 5); + const std::vector> *children = object->GetChildren(); + ASSERT_NE(children, nullptr); + EXPECT_EQ((int)children->size(), 0); +} + +HWTEST_F_L0(DebuggerTypesTest, SamplingHeapProfileNodeToJsonTest) +{ + std::string msg; + std::unique_ptr samplingHeapProfileNode; + std::string tmpStr; + std::unique_ptr tmpJson; + int32_t tmpInt; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "callFrame": {"functionName":"Create", "scriptId":"10", "url":"url3", "lineNumber":100, "columnNumber":20}, + "selfSize":10, + "id":5, + "children":[] + }})"; + samplingHeapProfileNode = SamplingHeapProfileNode::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(samplingHeapProfileNode, nullptr); + auto json = samplingHeapProfileNode->ToJson(); + + ret = json->GetObject("callFrame", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("functionName", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "Create"); + ret = tmpJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "10"); + ret = tmpJson->GetString("url", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "url3"); + + ret = json->GetInt("selfSize", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 10); + ret = json->GetInt("id", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 5); + ret = json->GetArray("children", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + EXPECT_EQ(tmpJson->GetSize(), 0); +} + +HWTEST_F_L0(DebuggerTypesTest, SamplingHeapProfileCreateTest) +{ + std::string msg; + std::unique_ptr object; + + // abnormal params of null msg + msg = std::string() + R"({})"; + object = SamplingHeapProfile::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + object = SamplingHeapProfile::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + object = SamplingHeapProfile::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + object = SamplingHeapProfile::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(object, nullptr); + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "head": { + "callFrame": {"functionName":"Create", "scriptId":"10", "url":"url3", "lineNumber":100, "columnNumber":20}, + "selfSize":10, + "id":5, + "children":[] + }, + "samples":[{"size":100, "nodeId":1, "ordinal":10}] + }})"; + object = SamplingHeapProfile::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(object, nullptr); + SamplingHeapProfileNode *head = object->GetHead(); + ASSERT_NE(head, nullptr); + + RuntimeCallFrame *runTimeCallFrame = head->GetCallFrame(); + ASSERT_NE(runTimeCallFrame, nullptr); + EXPECT_EQ(runTimeCallFrame->GetFunctionName(), "Create"); + EXPECT_EQ(runTimeCallFrame->GetScriptId(), "10"); + EXPECT_EQ(runTimeCallFrame->GetUrl(), "url3"); + EXPECT_EQ(runTimeCallFrame->GetLineNumber(), 100); + EXPECT_EQ(runTimeCallFrame->GetColumnNumber(), 20); + + EXPECT_EQ(head->GetSelfSize(), 10); + EXPECT_EQ(head->GetId(), 5); + const std::vector> *children = head->GetChildren(); + ASSERT_NE(children, nullptr); + EXPECT_EQ((int)children->size(), 0); + + const std::vector> *samples = object->GetSamples(); + ASSERT_NE(samples, nullptr); + EXPECT_EQ((int)samples->size(), 1); + EXPECT_EQ(samples->data()->get()->GetSize(), 100); + EXPECT_EQ(samples->data()->get()->GetNodeId(), 1); + EXPECT_EQ(samples->data()->get()->GetOrdinal(), 10); +} + +HWTEST_F_L0(DebuggerTypesTest, SamplingHeapProfileToJsonTest) +{ + std::string msg; + std::unique_ptr samplingHeapProfile; + std::string tmpStr; + int32_t tmpInt; + std::unique_ptr tmpJson; + std::unique_ptr varTmpJson; + std::unique_ptr exTmpJson; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "head": { + "callFrame": {"functionName":"Create", "scriptId":"10", "url":"url3", "lineNumber":100, "columnNumber":20}, + "selfSize":10, + "id":5, + "children":[] + }, + "samples":[{"size":100, "nodeId":1, "ordinal":10}] + }})"; + + samplingHeapProfile = SamplingHeapProfile::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(samplingHeapProfile, nullptr); + auto json = samplingHeapProfile->ToJson(); + + ret = json->GetObject("head", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetObject("callFrame", &varTmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(varTmpJson, nullptr); + ret = varTmpJson->GetString("functionName", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "Create"); + ret = varTmpJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "10"); + ret = varTmpJson->GetString("url", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "url3"); + + ret = tmpJson->GetInt("selfSize", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 10); + ret = tmpJson->GetInt("id", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 5); + ret = tmpJson->GetArray("children", &exTmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(exTmpJson, nullptr); + EXPECT_EQ(exTmpJson->GetSize(), 0); + + ret = json->GetArray("samples", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + EXPECT_EQ(tmpJson->GetSize(), 1); +} + +HWTEST_F_L0(DebuggerTypesTest, PositionTickInfoCreateTest) +{ + std::string msg; + std::unique_ptr positionTickInfo; + + // abnormal params of null msg + msg = std::string() + R"({})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(positionTickInfo, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(positionTickInfo, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(positionTickInfo, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(positionTickInfo, nullptr); + + // abnormal params of params.sub-key=["line":11,"ticks":99] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "line":"11","ticks":99}})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(positionTickInfo, nullptr); + + // abnormal params of params.sub-key=["line":"11","ticks":"99"] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "line":"11","ticks":"99"}})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(positionTickInfo, nullptr); + + // abnormal params of params.sub-key=["line":[11],"ticks":[99]] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "line":[11],"ticks":[99]}})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(positionTickInfo, nullptr); + + // normal params of params.sub-key=["line":11,"ticks":99] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"line":1,"ticks":0}})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(positionTickInfo, nullptr); + EXPECT_EQ(positionTickInfo->GetLine(), 1); + EXPECT_EQ(positionTickInfo->GetTicks(), 0); +} + +HWTEST_F_L0(DebuggerTypesTest, PositionTickInfoToJsonTest) +{ + std::string msg; + std::unique_ptr positionTickInfo; + int32_t tmpInt; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"line":1,"ticks":0}})"; + positionTickInfo = PositionTickInfo::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(positionTickInfo, nullptr); + auto json = positionTickInfo->ToJson(); + + ret = json->GetInt("line", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 1); + + ret = json->GetInt("ticks", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 0); +} + +HWTEST_F_L0(DebuggerTypesTest, ProfileNodeCreateTest) +{ + std::string msg; + std::unique_ptr profileNode; + + // abnormal params of null msg + msg = std::string() + R"({})"; + profileNode = ProfileNode::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(profileNode, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + profileNode = ProfileNode::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(profileNode, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + profileNode = ProfileNode::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(profileNode, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + profileNode = ProfileNode::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(profileNode, nullptr); + + // normal params of params.sub-key=[..] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "id":10, + "callFrame": {"functionName":"name0", "scriptId":"12", "url":"url15", "lineNumber":11, "columnNumber":20}, + "hitCount":15,"children":[],"positionTicks":[],"deoptReason":"yyy"}})"; + profileNode = ProfileNode::Create(DispatchRequest(msg).GetParams()); + + ASSERT_NE(profileNode, nullptr); + EXPECT_EQ(profileNode->GetId(), 10); + RuntimeCallFrame *runTimeCallFrame = profileNode->GetCallFrame(); + ASSERT_NE(runTimeCallFrame, nullptr); + EXPECT_EQ(runTimeCallFrame->GetFunctionName(), "name0"); + EXPECT_EQ(runTimeCallFrame->GetScriptId(), "12"); + EXPECT_EQ(runTimeCallFrame->GetUrl(), "url15"); + EXPECT_EQ(runTimeCallFrame->GetLineNumber(), 11); + EXPECT_EQ(runTimeCallFrame->GetColumnNumber(), 20); + + EXPECT_EQ(profileNode->GetHitCount(), 15); + EXPECT_EQ(profileNode->GetDeoptReason(), "yyy"); +} + +HWTEST_F_L0(DebuggerTypesTest, ProfileNodeToJsonTest) +{ + std::string msg; + std::unique_ptr profilenode; + std::string tmpStr; + int32_t tmpInt; + std::unique_ptr tmpJson; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "id":10, + "callFrame": {"functionName":"name0", "scriptId":"12", "url":"url15", "lineNumber":11, "columnNumber":20}, + "hitCount":15,"children":[],"positionTicks":[],"deoptReason":"yyy"}})"; + profilenode = ProfileNode::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(profilenode, nullptr); + auto json = profilenode->ToJson(); + + ret = json->GetInt("id", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 10); + + ret = json->GetObject("callFrame", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + ret = tmpJson->GetString("functionName", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "name0"); + ret = tmpJson->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "12"); + ret = tmpJson->GetString("url", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "url15"); + ret = tmpJson->GetInt("lineNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 11); + ret = tmpJson->GetInt("columnNumber", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 20); + + ret = json->GetInt("hitCount", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 15); + + ret = json->GetString("deoptReason", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "yyy"); +} + +HWTEST_F_L0(DebuggerTypesTest, ProfileCreateTest) +{ + std::string msg; + std::unique_ptr profile; + + // abnormal params of null msg + msg = std::string() + R"({})"; + profile = Profile::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(profile, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + profile = Profile::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(profile, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + profile = Profile::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(profile, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + profile = Profile::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(profile, nullptr); + + // abnormal params of params.sub-key=[..] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "startTime":10, "endTime":25, "nodes":[{"id":12, + "callFrame": {"functionName":"Create", "scriptId":"10", "url":"url3", "lineNumber":100, "columnNumber":20}}], + "samples":[],"timeDeltas":[]}})"; + profile = Profile::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(profile, nullptr); + + EXPECT_EQ(profile->GetStartTime(), 10LL); + EXPECT_EQ(profile->GetEndTime(), 25LL); + const std::vector> *profileNode = profile->GetNodes(); + ASSERT_NE(profileNode, nullptr); + EXPECT_EQ((int)profileNode->size(), 1); +} + +HWTEST_F_L0(DebuggerTypesTest, ProfileToJsonTest) +{ + std::string msg; + std::unique_ptr profile; + std::string tmpStr; + int32_t tmpInt; + std::unique_ptr tmpJson; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "startTime":10, "endTime":25, "nodes":[{"id":12, + "callFrame": {"functionName":"Create", "scriptId":"10", "url":"url3", "lineNumber":100, "columnNumber":20}}], + "samples":[],"timeDeltas":[]}})"; + profile = Profile::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(profile, nullptr); + auto json = profile->ToJson(); + + ret = json->GetInt("startTime", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 10); + + ret = json->GetInt("endTime", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 25); +} + +HWTEST_F_L0(DebuggerTypesTest, CoverageCreateTest) +{ + std::string msg; + std::unique_ptr coverage; + + // abnormal params of null msg + msg = std::string() + R"({})"; + coverage = Coverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(coverage, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + coverage = Coverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(coverage, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + coverage = Coverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(coverage, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + coverage = Coverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(coverage, nullptr); + + // normal params of params.sub-key=["startOffset":0,"endOffset":5,"count":13] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "startOffset":0,"endOffset":13,"count":13}})"; + coverage = Coverage::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(coverage, nullptr); + EXPECT_EQ(coverage->GetStartOffset(), 0); + EXPECT_EQ(coverage->GetEndOffset(), 13); + EXPECT_EQ(coverage->GetCount(), 13); +} + +HWTEST_F_L0(DebuggerTypesTest, CoverageToJsonTest) +{ + std::string msg; + std::unique_ptr coverage; + std::string tmpStr; + int32_t tmpInt; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "startOffset":0,"endOffset":13,"count":13}})"; + coverage = Coverage::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(coverage, nullptr); + auto json = coverage->ToJson(); + + ret = json->GetInt("startOffset", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 0); + + ret = json->GetInt("endOffset", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 13); + + ret = json->GetInt("count", &tmpInt); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpInt, 13); +} + +HWTEST_F_L0(DebuggerTypesTest, FunctionCoverageCreateTest) +{ + std::string msg; + std::unique_ptr functionCoverage; + + // abnormal params of null msg + msg = std::string() + R"({})"; + functionCoverage = FunctionCoverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(functionCoverage, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + functionCoverage = FunctionCoverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(functionCoverage, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + functionCoverage = FunctionCoverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(functionCoverage, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + functionCoverage = FunctionCoverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(functionCoverage, nullptr); + + // normal params of params.sub-key=[..] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "functionName":"Create0","ranges":[{"startOffset":0,"endOffset":13,"count":13}],"isBlockCoverage":true}})"; + functionCoverage = FunctionCoverage::Create(DispatchRequest(msg).GetParams()); + + ASSERT_NE(functionCoverage, nullptr); + EXPECT_EQ(functionCoverage->GetFunctionName(), "Create0"); + const std::vector> *ranges = functionCoverage->GetRanges(); + ASSERT_NE(ranges, nullptr); + EXPECT_EQ((int)ranges->size(), 1); + ASSERT_TRUE(functionCoverage->GetIsBlockCoverage()); +} + +HWTEST_F_L0(DebuggerTypesTest, FunctionCoverageToJsonTest) +{ + std::string msg; + std::unique_ptr functionCoverage; + std::string tmpStr; + bool tmpBool; + std::unique_ptr tmpJson; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "functionName":"Create0","ranges":[{"startOffset":0,"endOffset":13,"count":13}],"isBlockCoverage":true}})"; + functionCoverage = FunctionCoverage::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(functionCoverage, nullptr); + auto json = functionCoverage->ToJson(); + + ret = json->GetString("functionName", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "Create0"); + + ret = json->GetArray("ranges", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + EXPECT_EQ(tmpJson->GetSize(), 1); + + ret = json->GetBool("isBlockCoverage", &tmpBool); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_TRUE(tmpBool); +} + +HWTEST_F_L0(DebuggerTypesTest, ScriptCoverageCreateTest) +{ + std::string msg; + std::unique_ptr scriptCoverage; + + // abnormal params of null msg + msg = std::string() + R"({})"; + scriptCoverage = ScriptCoverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(scriptCoverage, nullptr); + + // abnormal params of unexist key params + msg = std::string() + R"({"id":0,"method":"Debugger.Test"})"; + scriptCoverage = ScriptCoverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(scriptCoverage, nullptr); + + // abnormal params of null params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + scriptCoverage = ScriptCoverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(scriptCoverage, nullptr); + + // abnormal params of unknown params.sub-key + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{"unknownKey":100}})"; + scriptCoverage = ScriptCoverage::Create(DispatchRequest(msg).GetParams()); + EXPECT_EQ(scriptCoverage, nullptr); + + // normal params of params.sub-key=[..] + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"1001", + "url":"url17", + "functions":[{"functionName":"Create0", + "ranges":[{"startOffset":0, "endOffset":13, "count":13}], + "isBlockCoverage":true}]}})"; + scriptCoverage = ScriptCoverage::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(scriptCoverage, nullptr); + EXPECT_EQ(scriptCoverage->GetScriptId(), "1001"); + EXPECT_EQ(scriptCoverage->GetUrl(), "url17"); + const std::vector> *functions = scriptCoverage->GetFunctions(); + ASSERT_NE(functions, nullptr); + EXPECT_EQ((int)functions->size(), 1); +} + +HWTEST_F_L0(DebuggerTypesTest, ScriptCoverageToJsonTest) +{ + std::string msg; + std::unique_ptr scriptCoverage; + std::string tmpStr; + std::unique_ptr tmpJson; + Result ret; + + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "scriptId":"1001", + "url":"url17", + "functions": [{"functionName":"Create0", + "ranges": [{"startOffset":0, "endOffset":13, "count":13}], + "isBlockCoverage":true}]}})"; + scriptCoverage = ScriptCoverage::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(scriptCoverage, nullptr); + auto json = scriptCoverage->ToJson(); + + ret = json->GetString("scriptId", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "1001"); + + ret = json->GetString("url", &tmpStr); + EXPECT_EQ(ret, Result::SUCCESS); + EXPECT_EQ(tmpStr, "url17"); + + ret = json->GetArray("functions", &tmpJson); + EXPECT_EQ(ret, Result::SUCCESS); + ASSERT_NE(tmpJson, nullptr); + EXPECT_EQ(tmpJson->GetSize(), 1); } +#endif } // namespace panda::test diff --git a/ecmascript/tooling/test/entry/test_debugger_entry.cpp b/ecmascript/tooling/test/entry/test_debugger_entry.cpp index c15d4bb41c3630ea367b63df8d1ef3ccbf5a299a..e10f6501e6ce9d149560807f27d821a2c24106f7 100644 --- a/ecmascript/tooling/test/entry/test_debugger_entry.cpp +++ b/ecmascript/tooling/test/entry/test_debugger_entry.cpp @@ -16,13 +16,13 @@ #include "ecmascript/tooling/test/utils/test_entry.h" namespace panda::ecmascript::tooling::test { -extern "C" int StartDebugger() +extern "C" bool StartDebug(const std::string &name, EcmaVM *vm, bool isDebugMode) { - return StartDebuggerImpl(); + return StartDebuggerImpl(name, vm, isDebugMode); } -extern "C" int StopDebugger() +extern "C" bool StopDebug(const std::string &name) { - return StopDebuggerImpl(); + return StopDebuggerImpl(name); } } // namespace panda::ecmascript::tooling::test diff --git a/ecmascript/tooling/test/js/ArrowFunc.js b/ecmascript/tooling/test/js/ArrowFunc.js new file mode 100644 index 0000000000000000000000000000000000000000..75e9b5fabff0f90330d8c72399ce9c83abde1a44 --- /dev/null +++ b/ecmascript/tooling/test/js/ArrowFunc.js @@ -0,0 +1,23 @@ +/* + * 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. + */ + +var sum = (num1, num2) => { + num1 = num1 + 1; + print(num1); + num2 = num2 + 1; + print(num2); + return num1 + num2; + }; +print(sum(1,2)); \ No newline at end of file diff --git a/ecmascript/tooling/test/js/AsyncFunc.js b/ecmascript/tooling/test/js/AsyncFunc.js new file mode 100644 index 0000000000000000000000000000000000000000..f9c0ac6481e5ee571cc2db6337f9fd1906c1b2bf --- /dev/null +++ b/ecmascript/tooling/test/js/AsyncFunc.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +async function helloAsync(){ + print ("helloAsync log 1"); + print ("helloAsync log 2"); + print ("helloAsync log 3"); + print ("helloAsync log 4"); + return "helloAsync"; +} + +print("main test 1"); +print(helloAsync()); +print("main test 2"); +print("main test 3"); + +helloAsync().then(v=>{ + print(v); + print("helloAsync then end!"); +}) +print("main test end!"); \ No newline at end of file diff --git a/ecmascript/tooling/test/js_pt_hooks_test.cpp b/ecmascript/tooling/test/js_pt_hooks_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cf27c5a82e177ffda15d266127eeb84effefbe04 --- /dev/null +++ b/ecmascript/tooling/test/js_pt_hooks_test.cpp @@ -0,0 +1,120 @@ +/* + * 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/js_array.h" +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/tests/test_helper.h" +#include "ecmascript/tooling/agent/debugger_impl.h" +#include "ecmascript/tooling/backend/js_pt_hooks.h" +#include "ecmascript/tooling/backend/js_debugger.h" +#include "ecmascript/tooling/base/pt_types.h" +#include "ecmascript/tooling/base/pt_events.h" +#include "ecmascript/tooling/dispatcher.h" + +using namespace panda::ecmascript; +using namespace panda::ecmascript::tooling; + +namespace panda::test { +class JSPtHooksTest : public testing::Test { +public: + using EntityId = panda_file::File::EntityId; + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + ecmaVm = EcmaVM::Cast(instance); + } + + void TearDown() override + { + TestHelper::DestroyEcmaVMWithScope(ecmaVm, scope); + } + +protected: + EcmaVM *ecmaVm {nullptr}; + PandaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +}; + +HWTEST_F_L0(JSPtHooksTest, BreakpointTest) +{ + auto debugger = std::make_unique(ecmaVm, nullptr, nullptr); + std::unique_ptr jspthooks = std::make_unique(debugger.get()); + const char *pandaFile = " "; + EntityId methodId(0); + uint32_t bytecodeOffset = 0; + JSPtLocation ptLocation1(pandaFile, methodId, bytecodeOffset); + jspthooks->Breakpoint(ptLocation1); + ASSERT_NE(jspthooks, nullptr); +} + +HWTEST_F_L0(JSPtHooksTest, LoadModuleTest) +{ + auto debugger = std::make_unique(ecmaVm, nullptr, nullptr); + std::unique_ptr jspthooks = std::make_unique(debugger.get()); + jspthooks->LoadModule("pandafile/test.abc"); + ASSERT_NE(jspthooks, nullptr); +} + +HWTEST_F_L0(JSPtHooksTest, ExceptionTest) +{ + auto debugger = std::make_unique(ecmaVm, nullptr, nullptr); + std::unique_ptr jspthooks = std::make_unique(debugger.get()); + const char *pandaFile = " "; + EntityId methodId(0); + uint32_t bytecodeOffset = 0; + JSPtLocation ptLocation2(pandaFile, methodId, bytecodeOffset); + jspthooks->Exception(ptLocation2); + ASSERT_NE(jspthooks, nullptr); +} + +HWTEST_F_L0(JSPtHooksTest, SingleStepTest) +{ + auto debugger = std::make_unique(ecmaVm, nullptr, nullptr); + std::unique_ptr jspthooks = std::make_unique(debugger.get()); + const char *pandaFile = " "; + EntityId methodId(0); + uint32_t bytecodeOffset = 0; + JSPtLocation ptLocation4(pandaFile, methodId, bytecodeOffset); + ASSERT_NE(jspthooks, nullptr); +} + +HWTEST_F_L0(JSPtHooksTest, VmStartTest) +{ + auto debugger = std::make_unique(ecmaVm, nullptr, nullptr); + std::unique_ptr jspthooks = std::make_unique(debugger.get()); + jspthooks->VmStart(); + ASSERT_NE(jspthooks, nullptr); +} + +HWTEST_F_L0(JSPtHooksTest, VmDeathTest) +{ + auto debugger = std::make_unique(ecmaVm, nullptr, nullptr); + std::unique_ptr jspthooks = std::make_unique(debugger.get()); + jspthooks->VmDeath(); + ASSERT_NE(jspthooks, nullptr); +} +} \ No newline at end of file diff --git a/ecmascript/tooling/test/pt_json_test.cpp b/ecmascript/tooling/test/pt_json_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..05997474df82e7a699eabaca00ea6c5b878a1354 --- /dev/null +++ b/ecmascript/tooling/test/pt_json_test.cpp @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/tests/test_helper.h" +#include "ecmascript/tooling/base/pt_json.h" + +using namespace panda::ecmascript::tooling; + +namespace panda::test { +class PtJsonTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + } + + void TearDown() override + { + } +}; + +HWTEST_F_L0(PtJsonTest, FalseTest) +{ + std::string str = "false"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsBool()); + EXPECT_FALSE(json->GetBool()); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, TrueTest) +{ + std::string str = "true"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsBool()); + EXPECT_TRUE(json->GetBool()); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, IntTest) +{ + std::string str = "100"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsNumber()); + EXPECT_EQ(json->GetInt(), 100); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, Int64Test) +{ + std::string str = "123456789012345"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsNumber()); + EXPECT_EQ(json->GetInt64(), 123456789012345); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, DoubleTest) +{ + std::string str = "12345.6789"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsNumber()); + EXPECT_EQ(json->GetDouble(), 12345.6789); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, StringTest) +{ + std::string str = "\"abcdefg\""; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsString()); + EXPECT_EQ(json->GetString(), "abcdefg"); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, ArrayTest1) +{ + std::string str = "[\"a\",\"b\",200]"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsArray()); + EXPECT_EQ(json->GetSize(), 3); + EXPECT_EQ(json->Get(0)->GetString(), "a"); + EXPECT_EQ(json->Get(1)->GetString(), "b"); + EXPECT_EQ(json->Get(2)->GetInt(), 200); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, ArrayTest2) +{ + std::string str = "[\"a\",\"b\",200,10.5,{}]"; + std::unique_ptr json = PtJson::Parse(str.c_str()); + ASSERT_TRUE(json->IsArray()); + EXPECT_EQ(json->GetSize(), 5); + EXPECT_EQ(json->Get(0)->GetString(), "a"); + EXPECT_EQ(json->Get(1)->GetString(), "b"); + EXPECT_EQ(json->Get(2)->GetInt(), 200); + EXPECT_EQ(json->Get(3)->GetDouble(), 10.5); + EXPECT_TRUE(json->Get(4)->IsObject()); + EXPECT_EQ(json->Stringify(), str); + json->ReleaseRoot(); +} + +HWTEST_F_L0(PtJsonTest, ObjectTest) +{ + auto child1 = PtJson::CreateObject(); + child1->Add("ch", "child_1"); + ASSERT_TRUE(child1->Contains("ch")); + + auto child2 = PtJson::CreateObject(); + child2->Add("ch", "child_2"); + ASSERT_TRUE(child2->Contains("ch")); + + auto arr = PtJson::CreateArray(); + arr->Push(100); + EXPECT_EQ(arr->GetSize(), 1); + + auto root = PtJson::CreateObject(); + root->Add("a", false); + root->Add("b", 100); + root->Add("c", 100.2); + root->Add("d", static_cast(200)); + root->Add("e", "abc"); + root->Add("f", child2); + root->Add("g", arr); + + bool b; + int32_t i32; + int64_t i64; + double d; + std::string str; + std::unique_ptr json; + ASSERT_EQ(root->GetBool("a", &b), Result::SUCCESS); + EXPECT_FALSE(b); + ASSERT_EQ(root->GetInt("b", &i32), Result::SUCCESS); + EXPECT_EQ(i32, 100); + ASSERT_EQ(root->GetDouble("c", &d), Result::SUCCESS); + EXPECT_EQ(d, 100.2); + ASSERT_EQ(root->GetInt64("d", &i64), Result::SUCCESS); + EXPECT_EQ(i64, static_cast(200)); + ASSERT_EQ(root->GetString("e", &str), Result::SUCCESS); + EXPECT_EQ(str, "abc"); + ASSERT_EQ(root->GetObject("f", &json), Result::SUCCESS); + ASSERT_EQ(json->GetString("ch", &str), Result::SUCCESS); + EXPECT_EQ(str, "child_2"); + ASSERT_EQ(root->GetArray("g", &json), Result::SUCCESS); + ASSERT_TRUE(json->IsArray()); + EXPECT_EQ(json->Get(0)->GetInt(), 100); + + EXPECT_EQ(root->Stringify(), + "{\"a\":false,\"b\":100,\"c\":100.2,\"d\":200,\"e\":\"abc\",\"f\":{\"ch\":\"child_2\"},\"g\":[100]}"); + root->ReleaseRoot(); +} +} \ No newline at end of file diff --git a/ecmascript/tooling/test/utils/test_entry.cpp b/ecmascript/tooling/test/utils/test_entry.cpp index df0e17adbad7219a96a83677961f3af735a148a4..5e3d90b47b873e55186b55f9478b013defbcf4ba 100644 --- a/ecmascript/tooling/test/utils/test_entry.cpp +++ b/ecmascript/tooling/test/utils/test_entry.cpp @@ -24,23 +24,22 @@ namespace panda::ecmascript::tooling::test { static std::thread g_debuggerThread; static std::unique_ptr g_hooks = nullptr; -int StartDebuggerImpl() +bool StartDebuggerImpl([[maybe_unused]] const std::string &name, EcmaVM *vm, [[maybe_unused]] bool isDebugMode) { - const char *testName = GetCurrentTestName(); - EcmaVM *vm = EcmaVM::Cast(Runtime::GetCurrent()->GetPandaVM()); + std::string testName = GetCurrentTestName(); g_hooks = std::make_unique(testName, vm); g_debuggerThread = std::thread([] { TestUtil::WaitForInit(); g_hooks->Run(); }); - return 0; + return true; } -int StopDebuggerImpl() +bool StopDebuggerImpl([[maybe_unused]] const std::string &name) { - g_debuggerThread.join(); g_hooks->TerminateTest(); + g_debuggerThread.join(); g_hooks.reset(); - return 0; + return true; } } // namespace panda::ecmascript::tooling::test diff --git a/ecmascript/tooling/test/utils/test_entry.h b/ecmascript/tooling/test/utils/test_entry.h index 53a1dde0e28d7ac621399ae87cff7cef59c3b620..0e6414a966161e7ee1635d35be2c3f8ccecb9268 100644 --- a/ecmascript/tooling/test/utils/test_entry.h +++ b/ecmascript/tooling/test/utils/test_entry.h @@ -16,9 +16,11 @@ #ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TEST_ENTRY_H #define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_ENTRY_H +#include "ecmascript/ecma_vm.h" + namespace panda::ecmascript::tooling::test { -int StartDebuggerImpl(); -int StopDebuggerImpl(); +bool StartDebuggerImpl(const std::string &name, EcmaVM *vm, bool isDebugMode); +bool StopDebuggerImpl(const std::string &name); } // namespace panda::ecmascript::tooling::test #endif // ECMASCRIPT_TOOLING_TEST_UTILS_TEST_ENTRY_H \ No newline at end of file diff --git a/ecmascript/tooling/test/utils/test_events.h b/ecmascript/tooling/test/utils/test_events.h index e42850de3ab1244d235490ffce18b75206610030..54e41ba60d26c21c55862ce955a9230c48b275d7 100644 --- a/ecmascript/tooling/test/utils/test_events.h +++ b/ecmascript/tooling/test/utils/test_events.h @@ -17,17 +17,15 @@ #define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_EVENTS_H #include -#include "ecmascript/tooling/agent/js_backend.h" -#include "ecmascript/tooling/agent/js_pt_hooks.h" + +#include "ecmascript/tooling/backend/js_pt_hooks.h" namespace panda::ecmascript::tooling::test { using BreakpointCallback = std::function; using LoadModuleCallback = std::function; -using PausedCallback = std::function; using ExceptionCallback = std::function; using SingleStepCallback = std::function; using VmStartCallback = std::function; -using VmInitializationCallback = std::function; using VmDeathCallback = std::function; using Scenario = std::function; @@ -49,20 +47,19 @@ std::ostream &operator<<(std::ostream &out, DebugEvent value); struct TestEvents { BreakpointCallback breakpoint; LoadModuleCallback loadModule; - PausedCallback paused; ExceptionCallback exception; SingleStepCallback singleStep; VmStartCallback vmStart; - VmInitializationCallback vmInit; VmDeathCallback vmDeath; Scenario scenario; + const EcmaVM *vm_ {nullptr}; JSDebugger *debugInterface_ {nullptr}; - JSBackend *backend_ {nullptr}; + DebuggerImpl *debugger_ {nullptr}; TestEvents(); virtual ~TestEvents() = default; - virtual std::pair GetEntryPoint() = 0; + virtual std::pair GetEntryPoint() = 0; }; } // namespace panda::ecmascript::tooling::test diff --git a/ecmascript/tooling/test/utils/test_extractor.cpp b/ecmascript/tooling/test/utils/test_extractor.cpp index 13a3dc824ff4aa43ecba3435435e4455e9abaccf..381c0a4c7a0a1856360dd45374216fdc0a8081b2 100644 --- a/ecmascript/tooling/test/utils/test_extractor.cpp +++ b/ecmascript/tooling/test/utils/test_extractor.cpp @@ -39,29 +39,19 @@ std::pair TestExtractor::GetBreakpointAddress(const SourceLo return {retId, retOffset}; } -std::vector TestExtractor::GetLocalVariableInfo(EntityId methodId, size_t offset) -{ - const std::vector &variables = GetLocalVariableTable(methodId); - std::vector result; - - for (const auto &variable : variables) { - if (variable.start_offset <= offset && offset <= variable.end_offset) { - result.push_back(variable); - } - } - return result; -} - SourceLocation TestExtractor::GetSourceLocation(EntityId methodId, uint32_t bytecodeOffset) { SourceLocation location {GetSourceFile(methodId), 0, 0}; - auto callbackFunc = [&location](size_t line, size_t column) -> bool { + auto callbackLineFunc = [&location](int32_t line) -> bool { location.line = line; + return true; + }; + auto callbackColumnFunc = [&location](int32_t column) -> bool { location.column = column; return true; }; - MatchWithOffset(callbackFunc, methodId, bytecodeOffset); - + MatchLineWithOffset(callbackLineFunc, methodId, bytecodeOffset); + MatchColumnWithOffset(callbackColumnFunc, methodId, bytecodeOffset); return location; } } // namespace panda::ecmascript::tooling::test diff --git a/ecmascript/tooling/test/utils/test_extractor.h b/ecmascript/tooling/test/utils/test_extractor.h index 2bcf825690ee0f70fe0b5e1eeda9bae415f3779c..5cc9bedc5c962f2ff939af4a2f77373c0edc4ec8 100644 --- a/ecmascript/tooling/test/utils/test_extractor.h +++ b/ecmascript/tooling/test/utils/test_extractor.h @@ -16,19 +16,16 @@ #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" +#include "ecmascript/tooling/backend/js_pt_extractor.h" namespace panda::ecmascript::tooling::test { using EntityId = panda_file::File::EntityId; -using panda::ecmascript::CString; -using panda::ecmascript::tooling::PtJSExtractor; // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) struct SourceLocation { - CString path; // NOLINT(misc-non-private-member-variables-in-classes) - size_t line; // NOLINT(misc-non-private-member-variables-in-classes) - size_t column; + std::string path; // NOLINT(misc-non-private-member-variables-in-classes) + int32_t line; // NOLINT(misc-non-private-member-variables-in-classes) + int32_t column; bool operator==(const SourceLocation &other) const { @@ -41,15 +38,13 @@ struct SourceLocation { } }; -class TestExtractor : public PtJSExtractor { +class TestExtractor : public JSPtExtractor { public: - explicit TestExtractor(const panda_file::File *pandaFileData) : PtJSExtractor(pandaFileData) {} + explicit TestExtractor(const JSPandaFile *pandaFile) : JSPtExtractor(pandaFile) {} ~TestExtractor() = default; std::pair GetBreakpointAddress(const SourceLocation &sourceLocation); - std::vector GetLocalVariableInfo(EntityId methodId, size_t offset); - SourceLocation GetSourceLocation(EntityId methodId, uint32_t bytecodeOffset); }; } // namespace panda::ecmascript::tooling::test diff --git a/ecmascript/tooling/test/utils/test_hooks.h b/ecmascript/tooling/test/utils/test_hooks.h index d0f582a33bf07a612a42d6b037f1799e646a8c0a..e5fa79c77b3a01fae02273a09b2faadc517d1a7c 100644 --- a/ecmascript/tooling/test/utils/test_hooks.h +++ b/ecmascript/tooling/test/utils/test_hooks.h @@ -16,21 +16,23 @@ #ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TEST_HOOKS_H #define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_HOOKS_H -#include "ecmascript/tooling/agent/js_pt_hooks.h" -#include "ecmascript/tooling/agent/js_backend.h" +#include "ecmascript/tooling/agent/debugger_impl.h" +#include "ecmascript/tooling/backend/js_pt_hooks.h" #include "ecmascript/tooling/test/utils/test_util.h" namespace panda::ecmascript::tooling::test { class TestHooks : public PtHooks { public: - TestHooks(const char *testName, const EcmaVM *vm) + TestHooks(const std::string &testName, const EcmaVM *vm) : vm_(vm) { - backend_ = std::make_unique(vm); + runtime_ = std::make_unique(vm, nullptr); + debugger_ = std::make_unique(vm, nullptr, runtime_.get()); testName_ = testName; test_ = TestUtil::GetTest(testName); - test_->backend_ = backend_.get(); - test_->debugInterface_ = backend_->GetDebugger(); - debugInterface_ = backend_->GetDebugger(); + test_->vm_ = vm; + test_->debugger_ = debugger_.get(); + test_->debugInterface_ = debugger_->jsDebugger_; + debugInterface_ = debugger_->jsDebugger_; TestUtil::Reset(); debugInterface_->RegisterHooks(this); } @@ -56,26 +58,20 @@ public: } } - void Paused(PauseReason reason) override - { - if (test_->paused) { - test_->paused(reason); - } - }; - void Exception(const JSPtLocation &location) override { if (test_->exception) { - Local exception = DebuggerApi::GetAndClearException(backend_->GetEcmaVm()); + Local exception = DebuggerApi::GetAndClearException(vm_); + test_->exception(location); if (!exception->IsHole()) { - DebuggerApi::SetException(backend_->GetEcmaVm(), exception); + DebuggerApi::SetException(vm_, exception); } } } - bool SingleStep(const JSPtLocation &location) override + bool SingleStep(const JSPtLocation &location) override { if (test_->singleStep) { return test_->singleStep(location); @@ -96,11 +92,14 @@ public: if (test_->vmStart) { test_->vmStart(); } + TestUtil::Event(DebugEvent::VM_START); } + void PendingJobEntry() override {} + void TerminateTest() { - debugInterface_->RegisterHooks(nullptr); + debugInterface_->UnregisterHooks(); if (TestUtil::IsTestFinished()) { return; } @@ -110,9 +109,11 @@ public: ~TestHooks() = default; private: - std::unique_ptr backend_ {nullptr}; + const EcmaVM *vm_ {nullptr}; + std::unique_ptr runtime_ {nullptr}; + std::unique_ptr debugger_ {nullptr}; JSDebugger *debugInterface_; - const char *testName_; + std::string testName_; TestEvents *test_; }; } // namespace panda::ecmascript::tooling::test diff --git a/ecmascript/tooling/test/utils/test_util.cpp b/ecmascript/tooling/test/utils/test_util.cpp index d343403c8eca4931bbe806422e257052d893b362..955fa1ff4b76b03a975b3b1fcaaf11473fd83b25 100644 --- a/ecmascript/tooling/test/utils/test_util.cpp +++ b/ecmascript/tooling/test/utils/test_util.cpp @@ -23,41 +23,9 @@ DebugEvent TestUtil::lastEvent_ = DebugEvent::UNINITIALIZED; bool TestUtil::initialized_ = false; os::memory::Mutex TestUtil::suspendMutex_; os::memory::ConditionVariable TestUtil::suspendCv_; -bool TestUtil::suspended_; +bool TestUtil::suspended_ = false; JSPtLocation TestUtil::lastEventLocation_("", EntityId(0), 0); -std::vector TestUtil::GetVariables(JSMethod *method, uint32_t offset) -{ - auto methodId = method->GetFileId(); - auto pandaFile = method->GetPandaFile()->GetFilename().c_str(); - PtLocation location(pandaFile, methodId, offset); - return GetVariables(location); -} - -std::vector TestUtil::GetVariables(PtLocation location) -{ - std::unique_ptr uFile = panda_file::File::Open(location.GetPandaFile()); - const panda_file::File *pf = uFile.get(); - if (pf == nullptr) { - return {}; - } - - TestExtractor extractor(pf); - return extractor.GetLocalVariableInfo(location.GetMethodId(), location.GetBytecodeOffset()); -} - -int32_t TestUtil::GetValueRegister(JSMethod *method, const char *varName) -{ - auto variables = TestUtil::GetVariables(method, 0); - for (const auto &var : variables) { - if (var.name == varName) { - return var.reg_number; - } - } - - return -1; -} - std::ostream &operator<<(std::ostream &out, DebugEvent value) { const char *s = nullptr; diff --git a/ecmascript/tooling/test/utils/test_util.h b/ecmascript/tooling/test/utils/test_util.h index 6fbd11fa2e4e755412c1d74c79a6bde9c50d3300..b438b0eb756859aad42c2ca12e0bcbc171d4756e 100644 --- a/ecmascript/tooling/test/utils/test_util.h +++ b/ecmascript/tooling/test/utils/test_util.h @@ -16,8 +16,9 @@ #ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TEST_UTIL_H #define ECMASCRIPT_TOOLING_TEST_UTILS_TEST_UTIL_H -#include "ecmascript/mem/c_containers.h" -#include "ecmascript/tooling/interface/js_debugger.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" +#include "ecmascript/tooling/agent/debugger_impl.h" +#include "ecmascript/tooling/backend/js_debugger.h" #include "ecmascript/tooling/test/utils/test_events.h" #include "ecmascript/tooling/test/utils/test_extractor.h" #include "os/mutex.h" @@ -25,30 +26,22 @@ namespace panda::ecmascript::tooling::test { template, class KeyEqual = std::equal_to> using CUnorderedMap = panda::ecmascript::CUnorderedMap; -using TestMap = CUnorderedMap>>; +using TestMap = CUnorderedMap>; class TestUtil { public: - static void RegisterTest(panda_file::SourceLang language, const char *testName, std::unique_ptr test) + static void RegisterTest(const std::string &testName, std::unique_ptr test) { - auto it = testMap_.find(language); - if (it == testMap_.end()) { - CUnorderedMap> entry; - auto res = testMap_.emplace(language, std::move(entry)); - it = res.first; - } - it->second.insert({testName, std::move(test)}); + testMap_.insert({testName, std::move(test)}); } - static TestEvents *GetTest(const char *name) + static TestEvents *GetTest(const std::string &name) { - for (auto it = testMap_.begin(); it != testMap_.end(); ++it) { - auto &internalMap = it->second; - auto internalIt = std::find_if(internalMap.begin(), internalMap.end(), - [name](auto &it) { return !::strcmp(it.first, name); }); - if (internalIt != internalMap.end()) { - return internalIt->second.get(); - } + auto iter = std::find_if(testMap_.begin(), testMap_.end(), [&name](auto &it) { + return it.first == name; + }); + if (iter != testMap_.end()) { + return iter->second.get(); } LOG(FATAL, DEBUGGER) << "Test " << name << " not found"; return nullptr; @@ -81,7 +74,7 @@ public: static bool WaitForInit() { - return WaitForEvent(DebugEvent::VM_INITIALIZATION, + return WaitForEvent(DebugEvent::VM_START, []() REQUIRES(eventMutex_) { return initialized_; }, [] {}); @@ -93,7 +86,7 @@ public: os::memory::LockHolder holder(eventMutex_); lastEvent_ = event; lastEventLocation_ = location; - if (event == DebugEvent::VM_INITIALIZATION) { + if (event == DebugEvent::VM_START) { initialized_ = true; } eventCv_.Signal(); @@ -119,49 +112,36 @@ public: static JSPtLocation GetLocation(const char *sourceFile, int32_t line, int32_t column, const char *pandaFile) { - std::unique_ptr uFile = panda_file::File::Open(pandaFile); - const panda_file::File *pf = uFile.get(); - if (pf == nullptr) { + auto jsPandaFile = ::panda::ecmascript::JSPandaFileManager::GetInstance()->LoadPfAbc(pandaFile); + if (jsPandaFile == nullptr) { return JSPtLocation("", EntityId(0), 0); } - TestExtractor extractor(pf); + TestExtractor extractor(jsPandaFile); auto [id, offset] = extractor.GetBreakpointAddress({sourceFile, line, column}); - return JSPtLocation("", EntityId(0), 0); + return JSPtLocation(pandaFile, id, offset); } static SourceLocation GetSourceLocation(const JSPtLocation &location, const char *pandaFile) { - std::unique_ptr uFile = panda_file::File::Open(pandaFile); - const panda_file::File *pf = uFile.get(); - if (pf == nullptr) { + auto jsPandaFile = ::panda::ecmascript::JSPandaFileManager::GetInstance()->LoadPfAbc(pandaFile); + if (jsPandaFile == nullptr) { return SourceLocation(); } - TestExtractor extractor(pf); + TestExtractor extractor(jsPandaFile); return extractor.GetSourceLocation(location.GetMethodId(), location.GetBytecodeOffset()); } - static std::vector GetVariables(JSMethod *method, uint32_t offset); - - static std::vector GetVariables(PtLocation location); - - static int32_t GetValueRegister(JSMethod *method, const char *varName); - static bool SuspendUntilContinue(DebugEvent reason, JSPtLocation location) { - { - os::memory::LockHolder lock(suspendMutex_); - suspended_ = true; - } + os::memory::LockHolder lock(suspendMutex_); + suspended_ = true; // Notify the debugger thread about the suspend event Event(reason, location); // Wait for continue - { - os::memory::LockHolder lock(suspendMutex_); - while (suspended_) { - suspendCv_.Wait(&suspendMutex_); - } + while (suspended_) { + suspendCv_.Wait(&suspendMutex_); } return true; @@ -184,7 +164,7 @@ private: if (lastEvent_ == DebugEvent::VM_DEATH) { return false; } - constexpr uint64_t TIMEOUT_MSEC = 100000U; + constexpr uint64_t TIMEOUT_MSEC = 10000U; bool timeExceeded = eventCv_.TimedWait(&eventMutex_, TIMEOUT_MSEC); if (timeExceeded) { LOG(FATAL, DEBUGGER) << "Time limit exceeded while waiting " << event; @@ -199,7 +179,7 @@ private: static os::memory::Mutex eventMutex_; static os::memory::ConditionVariable eventCv_ GUARDED_BY(eventMutex_); static DebugEvent lastEvent_ GUARDED_BY(eventMutex_); - static JSPtLocation lastEventLocation_ GUARDED_BY(eventMutex_); + static JSPtLocation lastEventLocation_ GUARDED_BY(eventMutex_); static os::memory::Mutex suspendMutex_; static os::memory::ConditionVariable suspendCv_ GUARDED_BY(suspendMutex_); static bool suspended_ GUARDED_BY(suspendMutex_); diff --git a/ecmascript/tooling/test/utils/testcases/js_breakpoint_arrow_test.h b/ecmascript/tooling/test/utils/testcases/js_breakpoint_arrow_test.h new file mode 100644 index 0000000000000000000000000000000000000000..e502c037e4e62878d9f6ffde4b706ef9576a4ee5 --- /dev/null +++ b/ecmascript/tooling/test/utils/testcases/js_breakpoint_arrow_test.h @@ -0,0 +1,89 @@ +/* + * 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_BREAKPOINT_ARROW_TEST_H +#define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_ARROW_TEST_H + +#include "ecmascript/tooling/test/utils/test_util.h" + +namespace panda::ecmascript::tooling::test { +class JsBreakpointArrowTest : public TestEvents { +public: + JsBreakpointArrowTest() + { + vmStart = [this] { + location_ = TestUtil::GetLocation("ArrowFunc.js", 18, 0, pandaFile_.c_str()); // 18: breakpointer line + ASSERT_TRUE(location_.GetMethodId().IsValid()); + return true; + }; + + breakpoint = [this](const JSPtLocation &location) { + ASSERT_TRUE(location.GetMethodId().IsValid()); + ASSERT_LOCATION_EQ(location, location_); + ++breakpointCounter_; + TestUtil::SuspendUntilContinue(DebugEvent::BREAKPOINT, location); + return true; + }; + + loadModule = [this](std::string_view moduleName) { + if (flag_) { + if (moduleName != pandaFile_) { + return true; + } + ASSERT_TRUE(debugger_->NotifyScriptParsed(0, pandaFile_)); + flag_ = false; + auto condFuncRef = FunctionRef::Undefined(vm_); + auto ret = debugInterface_->SetBreakpoint(location_, condFuncRef); + ASSERT_TRUE(ret); + } + return true; + }; + + scenario = [this]() { + ASSERT_BREAKPOINT_SUCCESS(location_); + TestUtil::Continue(); + auto ret = debugInterface_->RemoveBreakpoint(location_); + ASSERT_TRUE(ret); + ASSERT_EXITED(); + return true; + }; + + vmDeath = [this]() { + ASSERT_EQ(breakpointCounter_, 1U); + return true; + }; + } + + std::pair GetEntryPoint() override + { + return {pandaFile_, entryPoint_}; + } + ~JsBreakpointArrowTest() = default; + +private: + std::string pandaFile_ = DEBUGGER_ABC_DIR "ArrowFunc.abc"; + std::string entryPoint_ = "_GLOBAL::func_main_0"; + JSPtLocation location_ {nullptr, JSPtLocation::EntityId(0), 0}; + size_t breakpointCounter_ = 0; + bool flag_ = true; +}; + +std::unique_ptr GetJsBreakpointArrowTest() +{ + return std::make_unique(); +} +} // namespace panda::ecmascript::tooling::test + +#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_ARROW_TEST_H diff --git a/ecmascript/tooling/test/utils/testcases/js_breakpoint_async_test.h b/ecmascript/tooling/test/utils/testcases/js_breakpoint_async_test.h new file mode 100644 index 0000000000000000000000000000000000000000..2c90269baa86b9f4c68ced80cc3727f5081583b8 --- /dev/null +++ b/ecmascript/tooling/test/utils/testcases/js_breakpoint_async_test.h @@ -0,0 +1,91 @@ +/* + * 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_BREAKPOINT_ASYNC_TEST_H +#define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_ASYNC_TEST_H + +#include "ecmascript/tooling/test/utils/test_util.h" + +namespace panda::ecmascript::tooling::test { +class JsBreakpointAsyncTest : public TestEvents { +public: + JsBreakpointAsyncTest() + { + vmStart = [this] { + location_ = TestUtil::GetLocation("AsyncFunc.js", 18, 0, pandaFile_.c_str()); // 18: breakpointer line + ASSERT_TRUE(location_.GetMethodId().IsValid()); + return true; + }; + + breakpoint = [this](const JSPtLocation &location) { + ASSERT_TRUE(location.GetMethodId().IsValid()); + ASSERT_LOCATION_EQ(location, location_); + ++breakpointCounter_; + TestUtil::SuspendUntilContinue(DebugEvent::BREAKPOINT, location); + return true; + }; + + loadModule = [this](std::string_view moduleName) { + if (flag_) { + if (moduleName != pandaFile_) { + return true; + } + ASSERT_TRUE(debugger_->NotifyScriptParsed(0, pandaFile_)); + flag_ = false; + auto condFuncRef = FunctionRef::Undefined(vm_); + auto ret = debugInterface_->SetBreakpoint(location_, condFuncRef); + ASSERT_TRUE(ret); + } + return true; + }; + + scenario = [this]() { + ASSERT_BREAKPOINT_SUCCESS(location_); + TestUtil::Continue(); + ASSERT_BREAKPOINT_SUCCESS(location_); + TestUtil::Continue(); + auto ret = debugInterface_->RemoveBreakpoint(location_); + ASSERT_TRUE(ret); + ASSERT_EXITED(); + return true; + }; + + vmDeath = [this]() { + ASSERT_EQ(breakpointCounter_, 2U); + return true; + }; + } + + std::pair GetEntryPoint() override + { + return {pandaFile_, entryPoint_}; + } + ~JsBreakpointAsyncTest() = default; + +private: + std::string pandaFile_ = DEBUGGER_ABC_DIR "AsyncFunc.abc"; + std::string entryPoint_ = "_GLOBAL::func_main_0"; + JSPtLocation location_ {nullptr, JSPtLocation::EntityId(0), 0}; + size_t breakpointCounter_ = 0; + bool flag_ = true; +}; + +std::unique_ptr GetJsBreakpointAsyncTest() +{ + return std::make_unique(); +} +} // namespace panda::ecmascript::tooling::test + +#endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_ASYNC_TEST_H diff --git a/ecmascript/tooling/test/utils/testcases/js_breakpoint_test.h b/ecmascript/tooling/test/utils/testcases/js_breakpoint_test.h index d7f5b45a0bbf9625d4464c8176e0da5460952479..a598d261669e910793fccc9991f3ca1b7fe3e0ff 100644 --- a/ecmascript/tooling/test/utils/testcases/js_breakpoint_test.h +++ b/ecmascript/tooling/test/utils/testcases/js_breakpoint_test.h @@ -16,7 +16,6 @@ #ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_TEST_H #define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_BREAKPOINT_TEST_H -#include "ecmascript/mem/c_string.h" #include "ecmascript/tooling/test/utils/test_util.h" namespace panda::ecmascript::tooling::test { @@ -30,7 +29,7 @@ public: return true; }; - breakpoint = [this](const JSPtLocation &locatioon) { + breakpoint = [this](const JSPtLocation &location) { ASSERT_TRUE(location.GetMethodId().IsValid()); ASSERT_LOCATION_EQ(location, location_); ++breakpointCounter_; @@ -43,11 +42,11 @@ public: if (moduleName != pandaFile_) { return true; } - ASSERT_TRUE(backend_->NotifyScriptParsed(0, pandaFile_)); + ASSERT_TRUE(debugger_->NotifyScriptParsed(0, pandaFile_)); flag_ = false; - auto condFuncRef = FunctionRef::Undefined(backend_->GetEcmaVm()); - auto error = debugInterface_->SetBreakpoint(location_, condFuncRef); - ASSERT_FALSE(error); + auto condFuncRef = FunctionRef::Undefined(vm_); + auto ret = debugInterface_->SetBreakpoint(location_, condFuncRef); + ASSERT_TRUE(ret); } return true; }; @@ -57,7 +56,8 @@ public: TestUtil::Continue(); ASSERT_BREAKPOINT_SUCCESS(location_); TestUtil::Continue(); - ASSERT_TRUE(debugInterface_->RemoveBreakpoint(location_)); + auto ret = debugInterface_->RemoveBreakpoint(location_); + ASSERT_TRUE(ret); ASSERT_EXITED(); return true; }; @@ -68,14 +68,15 @@ public: }; } - std::pair GetEntryPoint() override + std::pair GetEntryPoint() override { return {pandaFile_, entryPoint_}; } ~JsBreakpointTest() = default; + private: - CString pandaFile_ = "/data/test/Sample.abc"; - CString entryPoint_ = "_GLOBAL::func_main_0"; + std::string pandaFile_ = DEBUGGER_ABC_DIR "Sample.abc"; + std::string entryPoint_ = "_GLOBAL::func_main_0"; JSPtLocation location_ {nullptr, JSPtLocation::EntityId(0), 0}; size_t breakpointCounter_ = 0; bool flag_ = true; diff --git a/ecmascript/tooling/test/utils/testcases/js_exception_test.h b/ecmascript/tooling/test/utils/testcases/js_exception_test.h index 74c017dea532191ad3da885fa9aaf211a10b2862..94b3b5317d037100e16c1ca340abab7e53e7a7da 100644 --- a/ecmascript/tooling/test/utils/testcases/js_exception_test.h +++ b/ecmascript/tooling/test/utils/testcases/js_exception_test.h @@ -16,7 +16,6 @@ #ifndef ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_EXCEPTION_TEST_H #define ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_JS_EXCEPTION_TEST_H -#include "ecmascript/mem/c_string.h" #include "ecmascript/tooling/test/utils/test_util.h" namespace panda::ecmascript::tooling::test { @@ -34,8 +33,8 @@ public: ASSERT_TRUE(location.GetMethodId().IsValid()); ASSERT_LOCATION_EQ(location, location_); ++breakpointCounter_; - CVector> callFrames; - ASSERT_TRUE(backend_->GenerateCallFrames(&callFrames)); + std::vector> callFrames; + ASSERT_TRUE(debugger_->GenerateCallFrames(&callFrames)); ASSERT_TRUE(callFrames.size() > 0); auto jsLocation = callFrames[0]->GetLocation(); ASSERT_TRUE(jsLocation != nullptr); @@ -50,8 +49,8 @@ public: ASSERT_EQ(sourceLocation.line, 17); ASSERT_EQ(sourceLocation.column, 27); ++exceptionCounter_; - CVector> callFrames; - ASSERT_TRUE(backend_->GenerateCallFrames(&callFrames)); + std::vector> callFrames; + ASSERT_TRUE(debugger_->GenerateCallFrames(&callFrames)); ASSERT_TRUE(callFrames.size() > 0); auto jsLocation = callFrames[0]->GetLocation(); ASSERT_TRUE(jsLocation != nullptr); @@ -66,11 +65,11 @@ public: if (moduleName != pandaFile_) { return true; } - ASSERT_TRUE(backend_->NotifyScriptParsed(0, pandaFile_)); + ASSERT_TRUE(debugger_->NotifyScriptParsed(0, pandaFile_)); flag_ = false; - auto condFuncRef = FunctionRef::Undefined(backend_->GetEcmaVm()); - auto error = debugInterface_->SetBreakpoint(location_, condFuncRef); - ASSERT_FALSE(error); + auto condFuncRef = FunctionRef::Undefined(vm_); + auto ret = debugInterface_->SetBreakpoint(location_, condFuncRef); + ASSERT_TRUE(ret); } return true; }; @@ -80,7 +79,8 @@ public: TestUtil::Continue(); TestUtil::WaitForException(); TestUtil::Continue(); - ASSERT_TRUE(debugInterface_->RemoveBreakpoint(location_)); + auto ret = debugInterface_->RemoveBreakpoint(location_); + ASSERT_TRUE(ret); ASSERT_EXITED(); return true; }; @@ -92,14 +92,15 @@ public: }; } - std::pair GetEntryPoint() override + std::pair GetEntryPoint() override { return {pandaFile_, entryPoint_}; } ~JsExceptionTest() = default; + private: - CString pandaFile_ = "/data/test/exception.abc"; - CString entryPoint_ = "_GLOBAL::func_main_0"; + std::string pandaFile_ = DEBUGGER_ABC_DIR "exception.abc"; + std::string entryPoint_ = "_GLOBAL::func_main_0"; JSPtLocation location_ {nullptr, JSPtLocation::EntityId(0), 0}; size_t breakpointCounter_ = 0; size_t exceptionCounter_ = 0; diff --git a/ecmascript/tooling/test/utils/testcases/js_single_step_test.h b/ecmascript/tooling/test/utils/testcases/js_single_step_test.h index 2c670ebec67ffd1102643dbfa819dfbba3b25f97..08cc43d5667dfa9eddf5d6e7d6511b910ba123b5 100644 --- a/ecmascript/tooling/test/utils/testcases/js_single_step_test.h +++ b/ecmascript/tooling/test/utils/testcases/js_single_step_test.h @@ -41,9 +41,9 @@ public: return true; } flag_ = false; - auto condFuncRef = FunctionRef::Undefined(backend_->GetEcmaVm()); - auto error = debugInterface_->SetBreakpoint(locationEnd_, condFuncRef); - ASSERT_FALSE(error); + auto condFuncRef = FunctionRef::Undefined(vm_); + auto ret = debugInterface_->SetBreakpoint(locationEnd_, condFuncRef); + ASSERT_TRUE(ret); } return true; }; @@ -77,14 +77,14 @@ public: }; } - std::pair GetEntryPoint() override + std::pair GetEntryPoint() override { return {pandaFile_, entryPoint_}; } private: - CString pandaFile_ = "/data/test/Sample.abc"; - CString entryPoint_ = "_GLOBAL::func_main_0"; + std::string pandaFile_ = DEBUGGER_ABC_DIR "Sample.abc"; + std::string entryPoint_ = "_GLOBAL::func_main_0"; JSPtLocation locationStart_ {nullptr, JSPtLocation::EntityId(0), 0}; JSPtLocation locationEnd_ {nullptr, JSPtLocation::EntityId(0), 0}; JSPtLocation locationStep_ {nullptr, JSPtLocation::EntityId(0), 0}; diff --git a/ecmascript/tooling/test/utils/testcases/test_list.cpp b/ecmascript/tooling/test/utils/testcases/test_list.cpp index 75fb3a2835dd5cb0aa081a5f11988d0e93a3b12b..2cb272b7006398dfaf1bdd8d45688679b49ce08a 100644 --- a/ecmascript/tooling/test/utils/testcases/test_list.cpp +++ b/ecmascript/tooling/test/utils/testcases/test_list.cpp @@ -19,47 +19,47 @@ // testcase list #include "js_breakpoint_test.h" +#include "js_breakpoint_arrow_test.h" +#include "js_breakpoint_async_test.h" #include "js_exception_test.h" #include "js_single_step_test.h" namespace panda::ecmascript::tooling::test { -static const char *g_currentTestName = nullptr; +static std::string g_currentTestName = ""; static void RegisterTests() { // Register testcases - TestUtil::RegisterTest(panda_file::SourceLang::ECMASCRIPT, "JsExceptionTest", GetJsExceptionTest()); - TestUtil::RegisterTest(panda_file::SourceLang::ECMASCRIPT, "JsSingleStepTest", GetJsSingleStepTest()); - TestUtil::RegisterTest(panda_file::SourceLang::ECMASCRIPT, "JsBreakpointTest", GetJsBreakpointTest()); + TestUtil::RegisterTest("JsExceptionTest", GetJsExceptionTest()); + TestUtil::RegisterTest("JsSingleStepTest", GetJsSingleStepTest()); + TestUtil::RegisterTest("JsBreakpointTest", GetJsBreakpointTest()); + TestUtil::RegisterTest("JsBreakpointAsyncTest", GetJsBreakpointAsyncTest()); + TestUtil::RegisterTest("JsBreakpointArrowTest", GetJsBreakpointArrowTest()); } -std::vector GetTestList(panda_file::SourceLang language) +std::vector GetTestList() { RegisterTests(); std::vector res; - auto &tests = TestUtil::GetTests(); - auto languageIt = tests.find(language); - if (languageIt == tests.end()) { - return {}; - } - for (const auto &entry : languageIt->second) { - res.push_back(entry.first); + auto &tests = TestUtil::GetTests(); + for (const auto &entry : tests) { + res.push_back(entry.first.c_str()); } return res; } -void SetCurrentTestName(const char *testName) +void SetCurrentTestName(const std::string &testName) { g_currentTestName = testName; } -const char *GetCurrentTestName() +std::string GetCurrentTestName() { return g_currentTestName; } -std::pair GetTestEntryPoint(const char *testName) +std::pair GetTestEntryPoint(const std::string &testName) { return TestUtil::GetTest(testName)->GetEntryPoint(); } diff --git a/ecmascript/tooling/test/utils/testcases/test_list.h b/ecmascript/tooling/test/utils/testcases/test_list.h index f81db0160dd5d46a4e012384f8441f9919610a5a..0f208fe16353fb3d89ca5f7a8df36765dd7177c0 100644 --- a/ecmascript/tooling/test/utils/testcases/test_list.h +++ b/ecmascript/tooling/test/utils/testcases/test_list.h @@ -19,18 +19,16 @@ #include #include +#include "ecmascript/mem/c_containers.h" #include "ecmascript/mem/c_string.h" -#include "libpandafile/file_items.h" namespace panda::ecmascript::tooling::test { -using panda::ecmascript::CString; +std::vector GetTestList(); -std::vector GetTestList(panda_file::SourceLang language); +void SetCurrentTestName(const std::string &testName); +std::string GetCurrentTestName(); -void SetCurrentTestName(const char *testName); -const char *GetCurrentTestName(); - -std::pair GetTestEntryPoint(const char *testName); +std::pair GetTestEntryPoint(const std::string &testName); } // namespace panda::ecmascript::tooling::test #endif // ECMASCRIPT_TOOLING_TEST_UTILS_TESTCASES_TEST_LIST_H diff --git a/ecmascript/ts_types/ts_type_table.cpp b/ecmascript/ts_types/ts_type_table.cpp index 0b9c994020ba764599e7059560d8c36db22dac83..7e21c42c385b627038d2e26c557eba4ea32c5580 100644 --- a/ecmascript/ts_types/ts_type_table.cpp +++ b/ecmascript/ts_types/ts_type_table.cpp @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "ecmascript/class_linker/program_object.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/js_handle.h" #include "ecmascript/literal_data_extractor.h" #include "ecmascript/object_factory.h" diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index 7ab88852b51bca01178c2f3ca385fa90351df4a5..7c367305acc1aea9869989c0835e439216231570 100755 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -18,13 +18,13 @@ group("ark_js_moduletest") { "bitwiseop:bitwiseopAction", "callframe:callframeAction", "class:classAction", - "container:containerAction", + # "container:containerAction", "dyninstruction:dyninstructionAction", "fortest:fortestAction", "generator:generatorAction", "getunmappedargs:getunmappedargsAction", "globalaccessor:globalaccessorAction", - "globalrecord:globalrecordAction", + # "globalrecord:globalrecordAction", "helloworld:helloworldAction", "lexicalenv:lexicalenvAction", "module:moduleAction", diff --git a/test/test_helper.gni b/test/test_helper.gni index 1bd9c1c80b23efbbdc4735c56cef909c32245131..32b09f0b6cdad3e56cdb3544de5b4a03c59292b1 100644 --- a/test/test_helper.gni +++ b/test/test_helper.gni @@ -17,9 +17,9 @@ import("//build/ohos.gni") import("//build/test.gni") if (is_standard_system) { - icu_path = "i18n_standard" + _icu_path_ = "common/common" } else { - icu_path = "i18n" + _icu_path_ = "global/i18n" } template("host_unittest_action") { @@ -54,7 +54,7 @@ template("host_unittest_action") { "--env-path", rebase_path(_root_out_dir_) + "/ark/ark:" + rebase_path(_root_out_dir_) + "/ark/ark_js_runtime:" + rebase_path(_root_out_dir_) + "/test/test:" + - rebase_path(_root_out_dir_) + "/global/${icu_path}:" + + rebase_path(_root_out_dir_) + "/${_icu_path_}:" + rebase_path("//prebuilts/clang/ohos/linux-x86_64/llvm/lib/"), ] @@ -137,7 +137,7 @@ template("host_moduletest_action") { "--env-path", rebase_path(_root_out_dir_) + "/ark/ark:" + rebase_path(_root_out_dir_) + "/ark/ark_js_runtime:" + rebase_path(_root_out_dir_) + - "/global/${icu_path}:" + + "/${_icu_path_}:" + rebase_path("//prebuilts/clang/ohos/linux-x86_64/llvm/lib/"), ]