From 48b026e531741a65748fdf34ecd885234466cdea Mon Sep 17 00:00:00 2001 From: huangtianzhi Date: Mon, 23 Dec 2024 17:27:43 +0800 Subject: [PATCH 1/2] Debugger scriptparsed optimization Issue: #IBD4GE Signed-off-by: huangtianzhi --- tooling/agent/debugger_impl.cpp | 227 ++++++++++++++---- tooling/agent/debugger_impl.h | 36 ++- tooling/backend/js_pt_hooks.cpp | 17 +- tooling/backend/js_pt_hooks.h | 1 + tooling/base/pt_events.cpp | 9 + tooling/base/pt_events.h | 7 + tooling/base/pt_json.cpp | 16 ++ tooling/base/pt_json.h | 3 + tooling/base/pt_params.cpp | 61 +++++ tooling/base/pt_params.h | 40 +++ tooling/base/pt_returns.h | 4 +- tooling/base/pt_script.h | 11 + tooling/base/pt_types.cpp | 12 + tooling/base/pt_types.h | 11 + tooling/client/domain/debugger_client.cpp | 55 +++++ tooling/client/domain/debugger_client.h | 2 + tooling/client/utils/cli_command.cpp | 9 + tooling/client/utils/cli_command.h | 1 + tooling/test/client_utils/test_list.cpp | 2 + tooling/test/debugger_impl_test.cpp | 37 +++ tooling/test/debugger_params_test.cpp | 39 +++ tooling/test/debugger_returns_test.cpp | 8 +- tooling/test/debugger_script_test.cpp | 12 + tooling/test/pt_json_test.cpp | 11 + .../testcases/js_accelerate_launch_test.h | 131 ++++++++++ tooling/test/utils/test_hooks.h | 2 + 26 files changed, 699 insertions(+), 65 deletions(-) create mode 100644 tooling/test/testcases/js_accelerate_launch_test.h diff --git a/tooling/agent/debugger_impl.cpp b/tooling/agent/debugger_impl.cpp index 4d111cb5..9428bac8 100755 --- a/tooling/agent/debugger_impl.cpp +++ b/tooling/agent/debugger_impl.cpp @@ -92,47 +92,40 @@ bool DebuggerImpl::NotifyScriptParsed(const std::string &fileName, std::string_v auto mainMethodIndex = panda_file::File::EntityId(jsPandaFile->GetMainMethodIndex(recordName)); const std::string &source = extractor->GetSourceCode(mainMethodIndex); const std::string &url = extractor->GetSourceFile(mainMethodIndex); - - recordNames_[url].insert(recordName); - // if load module, it needs to check whether clear singlestepper_ ClearSingleStepper(); if (MatchUrlAndFileName(url, fileName)) { + LOG_DEBUGGER(WARN) << "DebuggerImpl::NotifyScriptParsed: Script already been parsed: " + << "url: " << url << " fileName: " << fileName; return false; } - urlFileNameMap_[url].insert(fileName); - - // Notify script parsed event - std::unique_ptr script = std::make_unique(g_scriptId++, fileName, url, source); - - frontend_.ScriptParsed(vm_, *script); - // Store parsed script in map - scripts_[script->GetScriptId()] = std::move(script); + SaveParsedScriptsAndUrl(fileName, url, recordName, source); return true; } -bool DebuggerImpl::SendableScriptParsed(const std::string &fileName, const std::string &url, - const std::string &source, const std::string &recordName) +std::vector> DebuggerImpl::SetBreakpointsWhenParsingScript(const std::string &url) { - if (!CheckScriptParsed(fileName)) { - return false; + std::vector> outLocations {}; + for (const auto &breakpoint : breakpointPendingMap_[url]) { + if (!ProcessSingleBreakpoint(*breakpoint, outLocations)) { + std::string invalidBpId = "invalid"; + std::shared_ptr bpInfo = std::make_shared(); + bpInfo->SetId(invalidBpId) + .SetLineNumber(breakpoint->GetLineNumber()) + .SetColumnNumber(breakpoint->GetColumnNumber()); + outLocations.emplace_back(bpInfo); + } } + return outLocations; +} - recordNames_[url].insert(recordName); - - // if load module, it needs to check whether clear singlestepper_ - ClearSingleStepper(); - - urlFileNameMap_[url].insert(fileName); - // Notify script parsed event - std::unique_ptr script = std::make_unique(g_scriptId++, fileName, url, source); - - frontend_.ScriptParsed(vm_, *script); - - // Store parsed script in map - scripts_[script->GetScriptId()] = std::move(script); - return true; +bool DebuggerImpl::NeedToSetBreakpointsWhenParsingScript(const std::string &url) +{ + if (breakpointPendingMap_.find(url) != breakpointPendingMap_.end()) { + return !breakpointPendingMap_[url].empty(); + } + return false; } bool DebuggerImpl::CheckScriptParsed([[maybe_unused]] const std::string &fileName) @@ -146,7 +139,7 @@ bool DebuggerImpl::CheckScriptParsed([[maybe_unused]] const std::string &fileNam } #endif - // The release application does not require scriptParsed + // check if Debugable flag is true in module.json if (!vm_->GetJsDebuggerManager()->IsDebugApp()) { return false; } @@ -154,8 +147,27 @@ bool DebuggerImpl::CheckScriptParsed([[maybe_unused]] const std::string &fileNam return true; } -bool DebuggerImpl::SendableMethodEntry(JSHandle method) +void DebuggerImpl::SaveParsedScriptsAndUrl(const std::string &fileName, const std::string &url, + const std::string &recordName, const std::string &source) +{ + // Save recordName to its corresponding url + recordNames_[url].insert(recordName); + // Save parsed fileName to its corresponding url + urlFileNameMap_[url].insert(fileName); + // Create and save script + std::shared_ptr script = std::make_shared(g_scriptId++, fileName, url, source); + scripts_[script->GetScriptId()] = script; + // Check if is launch accelerate mode & has pending bps to set + if (IsLaunchAccelerateMode() && NeedToSetBreakpointsWhenParsingScript(url)) { + script->SetLocations(SetBreakpointsWhenParsingScript(url)); + } + // Notify frontend ScriptParsed event + frontend_.ScriptParsed(vm_, *script); +} + +bool DebuggerImpl::NotifyScriptParsedBySendable(JSHandle method) { + // Find extractor and retrieve infos const JSPandaFile *jsPandaFile = method->GetJSPandaFile(); if (jsPandaFile == nullptr) { LOG_DEBUGGER(ERROR) << "JSPandaFile is nullptr"; @@ -169,14 +181,23 @@ bool DebuggerImpl::SendableMethodEntry(JSHandle method) auto methodId = method->GetMethodId(); const std::string &url = extractor->GetSourceFile(methodId); const std::string &fileName = std::string(jsPandaFile->GetJSPandaFileDesc()); - if (!MatchUrlAndFileName(url, fileName)) { - // scriptParsed - const std::string &source = extractor->GetSourceCode(methodId); - const std::string &recordName = std::string(method->GetRecordNameStr()); - SendableScriptParsed(fileName, url, source, recordName); - return true; + // Check url path & is debugable in module.json + if (!CheckScriptParsed(fileName)) { + return false; } - return false; + // Clear SingleStepper before notify + ClearSingleStepper(); + // Check if this (url, fileName) pair has already been parsed + if (MatchUrlAndFileName(url, fileName)) { + LOG_DEBUGGER(WARN) << "DebuggerImpl::NotifyScriptParsedBySendable: Script already been parsed: " + << "url: " << url << " fileName: " << fileName; + return false; + } + // Parse and save this file + const std::string &source = extractor->GetSourceCode(methodId); + const std::string &recordName = std::string(method->GetRecordNameStr()); + SaveParsedScriptsAndUrl(fileName, url, recordName, source); + return true; } bool DebuggerImpl::MatchUrlAndFileName(const std::string &url, const std::string &fileName) @@ -184,7 +205,6 @@ bool DebuggerImpl::MatchUrlAndFileName(const std::string &url, const std::string auto urlFileNameIter = urlFileNameMap_.find(url); if (urlFileNameIter != urlFileNameMap_.end()) { if (urlFileNameIter->second.find(fileName) != urlFileNameIter->second.end()) { - LOG_DEBUGGER(WARN) << "MatchUrlAndFileName: already loaded: " << url; return true; } } @@ -449,7 +469,8 @@ void DebuggerImpl::InitializeExtendedProtocolsList() "setNativeRange", "resetSingleStepper", "callFunctionOn", - "smartStepInto" + "smartStepInto", + "saveAllPossibleBreakpoints" }; debuggerExtendedProtocols_ = std::move(debuggerProtocolList); } @@ -543,6 +564,9 @@ void DebuggerImpl::DispatcherImpl::Dispatch(const DispatchRequest &request) case Method::CALL_FUNCTION_ON: CallFunctionOn(request); break; + case Method::SAVE_ALL_POSSIBLE_BREAKPOINTS: + SaveAllPossibleBreakpoints(request); + break; default: SendResponse(request, DispatchResponse::Fail("Unknown method: " + request.GetMethod())); break; @@ -607,6 +631,8 @@ DebuggerImpl::DispatcherImpl::Method DebuggerImpl::DispatcherImpl::GetMethodEnum return Method::CLIENT_DISCONNECT; } else if (method == "callFunctionOn") { return Method::CALL_FUNCTION_ON; + } else if (method == "saveAllPossibleBreakpoints") { + return Method::SAVE_ALL_POSSIBLE_BREAKPOINTS; } else { return Method::UNKNOWN; } @@ -771,12 +797,24 @@ void DebuggerImpl::DispatcherImpl::GetPossibleAndSetBreakpointByUrl(const Dispat return; } - std::vector> outLocation; + std::vector> outLocation; DispatchResponse response = debugger_->GetPossibleAndSetBreakpointByUrl(*params, outLocation); GetPossibleAndSetBreakpointByUrlReturns result(std::move(outLocation)); SendResponse(request, response, result); } +void DebuggerImpl::DispatcherImpl::SaveAllPossibleBreakpoints(const DispatchRequest &request) +{ + std::unique_ptr params = + SaveAllPossibleBreakpointsParams::Create(request.GetParams()); + if (params == nullptr) { + SendResponse(request, DispatchResponse::Fail("wrong params")); + return; + } + DispatchResponse response = debugger_->SaveAllPossibleBreakpoints(*params); + SendResponse(request, response); +} + void DebuggerImpl::DispatcherImpl::SetPauseOnExceptions(const DispatchRequest &request) { std::unique_ptr params = SetPauseOnExceptionsParams::Create(request.GetParams()); @@ -1008,7 +1046,8 @@ void DebuggerImpl::Frontend::ScriptParsed(const EcmaVM *vm, const PtScript &scri .SetEndLine(script.GetEndLine()) .SetEndColumn(0) .SetExecutionContextId(0) - .SetHash(script.GetHash()); + .SetHash(script.GetHash()) + .SetLocations(script.GetLocations()); channel_->SendNotification(scriptParsed); } @@ -1045,6 +1084,8 @@ DispatchResponse DebuggerImpl::Enable([[maybe_unused]] const EnableParams ¶m ASSERT(id != nullptr); *id = 0; vm_->GetJsDebuggerManager()->SetDebugMode(true); + // Enable corresponding features requested by IDE + EnableDebuggerFeatures(params); for (auto &script : scripts_) { frontend_.ScriptParsed(vm_, *script.second); } @@ -1052,6 +1093,42 @@ DispatchResponse DebuggerImpl::Enable([[maybe_unused]] const EnableParams ¶m return DispatchResponse::Ok(); } +void DebuggerImpl::EnableDebuggerFeatures(const EnableParams ¶ms) +{ + if (!params.HasEnableOptionsList()) { + return; + } + auto enableOptionsList = params.GetEnableOptionsList(); + if (enableOptionsList.empty()) { + return; + } + for (auto &option : enableOptionsList) { + LOG_DEBUGGER(INFO) << "Debugger feature " << option << " is enabled"; + EnableFeature(GetDebuggerFeatureEnum(option)); + } +} + +DebuggerFeature DebuggerImpl::GetDebuggerFeatureEnum(std::string &option) +{ + if (option == "enableLaunchAccelerate") { + return DebuggerFeature::LAUNCH_ACCELERATE; + } + // Future features could be added here to parse as DebuggerFeatureEnum + return DebuggerFeature::UNKNOWN; +} + +void DebuggerImpl::EnableFeature(DebuggerFeature feature) +{ + switch (feature) { + case DebuggerFeature::LAUNCH_ACCELERATE: + EnableLaunchAccelerateMode(); + DebuggerApi::DisableFirstTimeFlag(jsDebugger_); + break; + default: + break; + } +} + DispatchResponse DebuggerImpl::Disable() { DebuggerApi::RemoveAllBreakpoints(jsDebugger_); @@ -1206,6 +1283,9 @@ DispatchResponse DebuggerImpl::RemoveBreakpointsByUrl(const RemoveBreakpointsByU } LOG_DEBUGGER(INFO) << "All breakpoints on " << url << " are removed"; + if (IsLaunchAccelerateMode()) { + breakpointPendingMap_.erase(url); + } return DispatchResponse::Ok(); } @@ -1300,7 +1380,7 @@ DispatchResponse DebuggerImpl::SetBreakpointsActive(const SetBreakpointsActivePa } DispatchResponse DebuggerImpl::GetPossibleAndSetBreakpointByUrl(const GetPossibleAndSetBreakpointParams ¶ms, - std::vector> &outLocations) + std::vector> &outLocations) { if (!vm_->GetJsDebuggerManager()->IsDebugMode()) { return DispatchResponse::Fail("GetPossibleAndSetBreakpointByUrl: debugger agent is not enabled"); @@ -1312,18 +1392,69 @@ DispatchResponse DebuggerImpl::GetPossibleAndSetBreakpointByUrl(const GetPossibl for (const auto &breakpoint : *breakpointList) { if (!ProcessSingleBreakpoint(*breakpoint, outLocations)) { std::string invalidBpId = "invalid"; - std::unique_ptr bpInfo = std::make_unique(); + std::shared_ptr bpInfo = std::make_shared(); bpInfo->SetId(invalidBpId) .SetLineNumber(breakpoint->GetLineNumber()) .SetColumnNumber(breakpoint->GetColumnNumber()); - outLocations.emplace_back(std::move(bpInfo)); + outLocations.emplace_back(bpInfo); + } + // Insert this bp into bp pending map + if (IsLaunchAccelerateMode()) { + InsertIntoPendingBreakpoints(*breakpoint); } } return DispatchResponse::Ok(); } +bool DebuggerImpl::InsertIntoPendingBreakpoints(const BreakpointInfo &breakpoint) +{ + auto condition = breakpoint.HasCondition() ? breakpoint.GetCondition() : std::optional {}; + auto bpShared = BreakpointInfo::CreateAsSharedPtr(breakpoint.GetLineNumber(), breakpoint.GetColumnNumber(), + breakpoint.GetUrl(), (condition.has_value() ? condition.value() : "")); + if (breakpointPendingMap_.empty() || + breakpointPendingMap_.find(breakpoint.GetUrl()) == breakpointPendingMap_.end()) { + CUnorderedSet, HashBreakpointInfo> set {}; + set.insert(bpShared); + breakpointPendingMap_[breakpoint.GetUrl()] = set; + return true; + } + return (breakpointPendingMap_[breakpoint.GetUrl()].insert(bpShared)).second; +} + +DispatchResponse DebuggerImpl::SaveAllPossibleBreakpoints(const SaveAllPossibleBreakpointsParams ¶ms) +{ + if (!vm_->GetJsDebuggerManager()->IsDebugMode()) { + return DispatchResponse::Fail("SaveAllPossibleBreakpoints: debugger agent is not enabled"); + } + if (!IsLaunchAccelerateMode()) { + return DispatchResponse::Fail("SaveAllPossibleBreakpoints: protocol is not enabled"); + } + if (!params.HasBreakpointsMap()) { + return DispatchResponse::Fail("SaveAllPossibleBreakpoints: no pending breakpoint exists"); + } + SavePendingBreakpoints(params); + return DispatchResponse::Ok(); +} + +void DebuggerImpl::SavePendingBreakpoints(const SaveAllPossibleBreakpointsParams ¶ms) +{ + for (const auto &entry : *(params.GetBreakpointsMap())) { + if (breakpointPendingMap_.find(entry.first) == breakpointPendingMap_.end()) { + CUnorderedSet, HashBreakpointInfo> set {}; + for (auto &info : entry.second) { + set.insert(info); + } + breakpointPendingMap_[entry.first] = set; + } else { + for (auto &info : entry.second) { + breakpointPendingMap_[entry.first].insert(info); + } + } + } +} + bool DebuggerImpl::ProcessSingleBreakpoint(const BreakpointInfo &breakpoint, - std::vector> &outLocations) + std::vector> &outLocations) { const std::string &url = breakpoint.GetUrl(); int32_t lineNumber = breakpoint.GetLineNumber(); @@ -1367,9 +1498,9 @@ bool DebuggerImpl::ProcessSingleBreakpoint(const BreakpointInfo &breakpoint, BreakpointDetails bpMetaData {lineNumber, 0, url}; std::string outId = BreakpointDetails::ToString(bpMetaData); - std::unique_ptr bpInfo = std::make_unique(); + std::shared_ptr bpInfo = std::make_unique(); bpInfo->SetScriptId(scriptId).SetLineNumber(lineNumber).SetColumnNumber(0).SetId(outId); - outLocations.emplace_back(std::move(bpInfo)); + outLocations.emplace_back(bpInfo); return true; } diff --git a/tooling/agent/debugger_impl.h b/tooling/agent/debugger_impl.h index c8b35633..9fd14336 100644 --- a/tooling/agent/debugger_impl.h +++ b/tooling/agent/debugger_impl.h @@ -32,6 +32,7 @@ class TestHooks; } // namespace test enum class DebuggerState { DISABLED, ENABLED, PAUSED }; +enum class DebuggerFeature { LAUNCH_ACCELERATE, UNKNOWN }; class DebuggerImpl final { public: DebuggerImpl(const EcmaVM *vm, ProtocolChannel *channel, RuntimeImpl *runtime); @@ -40,10 +41,8 @@ public: // event bool NotifyScriptParsed(const std::string &fileName, std::string_view entryPoint = "func_main_0"); - bool SendableScriptParsed(const std::string &fileName, const std::string &url, - const std::string &source, const std::string &recordName); bool CheckScriptParsed(const std::string &fileName); - bool SendableMethodEntry(JSHandle method); + bool NotifyScriptParsedBySendable(JSHandle method); bool MatchUrlAndFileName(const std::string &url, const std::string &fileName); bool NotifySingleStep(const JSPtLocation &location); void NotifyPaused(std::optional location, PauseReason reason); @@ -79,7 +78,7 @@ public: bool isSmartBreakpoint = false); DispatchResponse SetBreakpointsActive(const SetBreakpointsActiveParams ¶ms); DispatchResponse GetPossibleAndSetBreakpointByUrl(const GetPossibleAndSetBreakpointParams ¶ms, - std::vector> &outLocations); + std::vector> &outLocations); DispatchResponse SetPauseOnExceptions(const SetPauseOnExceptionsParams ¶ms); DispatchResponse SetSkipAllPauses(const SetSkipAllPausesParams ¶ms); DispatchResponse SetNativeRange(const SetNativeRangeParams ¶ms); @@ -97,7 +96,7 @@ public: const CallFunctionOnParams ¶ms, std::unique_ptr *outRemoteObject, std::optional> *outExceptionDetails); - + DispatchResponse SaveAllPossibleBreakpoints(const SaveAllPossibleBreakpointsParams ¶ms); /** * @brief: match first script and callback * @@ -179,6 +178,7 @@ public: void DropFrame(const DispatchRequest &request); void ClientDisconnect(const DispatchRequest &request); void CallFunctionOn(const DispatchRequest &request); + void SaveAllPossibleBreakpoints(const DispatchRequest &request); enum class Method { CONTINUE_TO_LOCATION, @@ -209,6 +209,7 @@ public: RESET_SINGLE_STEPPER, CLIENT_DISCONNECT, CALL_FUNCTION_ON, + SAVE_ALL_POSSIBLE_BREAKPOINTS, UNKNOWN }; Method GetMethodEnum(const std::string& method); @@ -252,10 +253,19 @@ private: bool CheckPauseOnException(); bool IsWithinVariableScope(const LocalVariableInfo &localVariableInfo, uint32_t bcOffset); bool ProcessSingleBreakpoint(const BreakpointInfo &breakpoint, - std::vector> &outLocations); + std::vector> &outLocations); bool IsVariableSkipped(const std::string &varName); Local CheckAndGenerateCondFunc(const std::optional &condition); void InitializeExtendedProtocolsList(); + bool NeedToSetBreakpointsWhenParsingScript(const std::string &url); + std::vector> SetBreakpointsWhenParsingScript(const std::string &url); + void SavePendingBreakpoints(const SaveAllPossibleBreakpointsParams ¶ms); + bool InsertIntoPendingBreakpoints(const BreakpointInfo &breakpoint); + void SaveParsedScriptsAndUrl(const std::string &fileName, const std::string &url, + const std::string &recordName, const std::string &source = ""); + void EnableDebuggerFeatures(const EnableParams ¶ms); + DebuggerFeature GetDebuggerFeatureEnum(std::string &option); + void EnableFeature(DebuggerFeature feature); const std::unordered_set &GetRecordName(const std::string &url) { @@ -266,6 +276,14 @@ private: } return recordName; } + void EnableLaunchAccelerateMode() + { + breakOnStartEnable_ = false; + } + bool IsLaunchAccelerateMode() const + { + return !breakOnStartEnable_; + } class Frontend { public: @@ -297,7 +315,7 @@ private: std::unordered_map> recordNames_ {}; std::unordered_map> urlFileNameMap_ {}; - std::unordered_map> scripts_ {}; + std::unordered_map> scripts_ {}; PauseOnExceptionsState pauseOnException_ {PauseOnExceptionsState::NONE}; DebuggerState debuggerState_ {DebuggerState::ENABLED}; bool pauseOnNextByteCode_ {false}; @@ -319,6 +337,10 @@ private: JsDebuggerManager::SingleStepperFunc stepperFunc_ {nullptr}; JsDebuggerManager::ReturnNativeFunc returnNative_ {nullptr}; std::vector debuggerExtendedProtocols_ {}; + // For launch accelerate mode + std::unordered_map, HashBreakpointInfo>> + breakpointPendingMap_ {}; + bool breakOnStartEnable_ {true}; friend class JSPtHooks; friend class test::TestHooks; diff --git a/tooling/backend/js_pt_hooks.cpp b/tooling/backend/js_pt_hooks.cpp index b704d8b6..4c484ed4 100644 --- a/tooling/backend/js_pt_hooks.cpp +++ b/tooling/backend/js_pt_hooks.cpp @@ -84,7 +84,9 @@ void JSPtHooks::LoadModule(std::string_view pandaFileName, std::string_view entr [[maybe_unused]] LocalScope scope(debugger_->vm_); if (debugger_->NotifyScriptParsed(pandaFileName.data(), entryPoint)) { - firstTime_ = true; + if (!debugger_->IsLaunchAccelerateMode()) { + firstTime_ = true; + } } } @@ -110,8 +112,15 @@ void JSPtHooks::SendableMethodEntry(JSHandle method) [[maybe_unused]] LocalScope scope(debugger_->vm_); - if (debugger_->SendableMethodEntry(method)) { - firstTime_ = true; - }; + if (debugger_->NotifyScriptParsedBySendable(method)) { + if (!debugger_->IsLaunchAccelerateMode()) { + firstTime_ = true; + } + } +} + +void JSPtHooks::DisableFirstTimeFlag() +{ + firstTime_ = false; } } // namespace panda::ecmascript::tooling diff --git a/tooling/backend/js_pt_hooks.h b/tooling/backend/js_pt_hooks.h index a8429053..58c76e4f 100644 --- a/tooling/backend/js_pt_hooks.h +++ b/tooling/backend/js_pt_hooks.h @@ -41,6 +41,7 @@ public: void VmStart() override {} void VmDeath() override {} void SendableMethodEntry(JSHandle method) override; + void DisableFirstTimeFlag() override; private: NO_COPY_SEMANTIC(JSPtHooks); diff --git a/tooling/base/pt_events.cpp b/tooling/base/pt_events.cpp index 88f7ef01..f3a4e608 100644 --- a/tooling/base/pt_events.cpp +++ b/tooling/base/pt_events.cpp @@ -191,6 +191,15 @@ std::unique_ptr ScriptParsed::ToJson() const result->Add("embedderName", embedderName_->c_str()); } + std::unique_ptr array = PtJson::CreateArray(); + size_t len = locations_.size(); + for (size_t i = 0; i < len; i++) { + ASSERT(locations_[i] != nullptr); + std::unique_ptr location = locations_[i]->ToJson(); + array->Push(location); + } + result->Add("locations", array); + std::unique_ptr object = PtJson::CreateObject(); object->Add("method", GetName().c_str()); object->Add("params", result); diff --git a/tooling/base/pt_events.h b/tooling/base/pt_events.h index 47aa85d5..9d1bea7e 100644 --- a/tooling/base/pt_events.h +++ b/tooling/base/pt_events.h @@ -808,6 +808,12 @@ public: return embedderName_.has_value(); } + ScriptParsed &SetLocations(std::vector> locations) + { + locations_ = locations; + return *this; + } + private: NO_COPY_SEMANTIC(ScriptParsed); NO_MOVE_SEMANTIC(ScriptParsed); @@ -829,6 +835,7 @@ private: std::optional codeOffset_ {}; std::optional scriptLanguage_ {}; std::optional embedderName_ {}; + std::vector> locations_ {}; }; class AddHeapSnapshotChunk final : public PtBaseEvents { diff --git a/tooling/base/pt_json.cpp b/tooling/base/pt_json.cpp index 94b592e7..d265606c 100644 --- a/tooling/base/pt_json.cpp +++ b/tooling/base/pt_json.cpp @@ -249,6 +249,22 @@ std::string PtJson::GetKey() const return std::string(object_->string); } +std::vector PtJson::GetKeysArray() const +{ + std::vector result; + if (object_ == nullptr) { + return result; + } + cJSON *node = object_->child; + while (node != nullptr) { + if (node->string != nullptr) { + result.emplace_back(std::string(node->string)); + } + node = node->next; + } + return result; +} + cJSON *PtJson::GetJson() const { return object_; diff --git a/tooling/base/pt_json.h b/tooling/base/pt_json.h index d66e0d7f..dcaa0b8b 100644 --- a/tooling/base/pt_json.h +++ b/tooling/base/pt_json.h @@ -18,6 +18,7 @@ #include #include +#include #include "cJSON.h" #include "common/macros.h" @@ -73,6 +74,8 @@ public: std::string GetKey() const; + std::vector GetKeysArray() const; + cJSON *GetJson() const; // Type check diff --git a/tooling/base/pt_params.cpp b/tooling/base/pt_params.cpp index 293db741..3f5934db 100644 --- a/tooling/base/pt_params.cpp +++ b/tooling/base/pt_params.cpp @@ -30,6 +30,22 @@ std::unique_ptr EnableParams::Create(const PtJson ¶ms) error += "Wrong type of 'maxScriptsCacheSize';"; } + std::unique_ptr options; + std::vector enableOptionsList; + ret = params.GetArray("options", &options); + if (ret == Result::SUCCESS) { + int32_t length = options->GetSize(); + for (int32_t i = 0; i < length; i++) { + auto option = options->Get(i); + if (option != nullptr && option->IsString()) { + enableOptionsList.emplace_back(option->GetString()); + } + } + paramsObject->enableOptionList_ = enableOptionsList; + } else if (ret == Result::TYPE_ERROR) { + error += "Wrong type of 'options';"; + } + if (!error.empty()) { LOG_DEBUGGER(ERROR) << "EnableParams::Create " << error; return nullptr; @@ -1301,4 +1317,49 @@ std::unique_ptr SeriliazationTimeoutCheck } return paramsObject; } + +std::unique_ptr SaveAllPossibleBreakpointsParams::Create(const PtJson ¶ms) +{ + auto paramsObject = std::make_unique(); + std::unordered_map>> breakpointMap {}; + std::string error; + Result ret; + + std::unique_ptr locationList; + ret = params.GetObject("locations", &locationList); + if (ret != Result::SUCCESS) { + LOG_DEBUGGER(ERROR) << "SaveAllPossibleBreakpointsParams::Get Breakpoints location: " << error; + return nullptr; + } + + auto keys = locationList->GetKeysArray(); + std::unique_ptr breakpoints; + for (const auto &key : keys) { + ret = locationList->GetArray(key.c_str(), &breakpoints); + if (ret == Result::SUCCESS) { + int32_t length = breakpoints->GetSize(); + std::vector> breakpointList; + for (int32_t i = 0; i < length; i++) { + auto json = *breakpoints->Get(i); + json.Add("url", key.c_str()); + std::shared_ptr info = BreakpointInfo::Create(json); + if (info == nullptr) { + error += "'breakpoints' items BreakpointInfo is invalid;"; + break; + } + breakpointList.emplace_back(std::move(info)); + } + breakpointMap[key] = breakpointList; + } else if (ret == Result::TYPE_ERROR) { + error += "Wrong type of 'breakpoints'"; + } + } + if (!error.empty()) { + LOG_DEBUGGER(ERROR) << "SaveAllPossibleBreakpointsParams::Create " << error; + return nullptr; + } + paramsObject->breakpointsMap_ = breakpointMap; + + return paramsObject; +} } // namespace panda::ecmascript::tooling diff --git a/tooling/base/pt_params.h b/tooling/base/pt_params.h index ea8a5110..404616ef 100644 --- a/tooling/base/pt_params.h +++ b/tooling/base/pt_params.h @@ -74,11 +74,23 @@ public: return maxScriptsCacheSize_.has_value(); } + bool HasEnableOptionsList() const + { + return enableOptionList_.has_value(); + } + + std::vector GetEnableOptionsList() const + { + ASSERT(HasEnableOptionsList()); + return enableOptionList_.value(); + } + private: NO_COPY_SEMANTIC(EnableParams); NO_MOVE_SEMANTIC(EnableParams); std::optional maxScriptsCacheSize_ {}; + std::optional> enableOptionList_ {}; }; class EvaluateOnCallFrameParams : public PtBaseParams { @@ -1370,5 +1382,33 @@ private: static constexpr int32_t DEFAULT_THRESHOLD = 8; int32_t threshold_ { DEFAULT_THRESHOLD }; }; + +class SaveAllPossibleBreakpointsParams : public PtBaseParams { +public: + SaveAllPossibleBreakpointsParams() = default; + ~SaveAllPossibleBreakpointsParams() = default; + + static std::unique_ptr Create(const PtJson ¶ms); + + const std::unordered_map>> *GetBreakpointsMap() const + { + if (!HasBreakpointsMap()) { + return nullptr; + } + return &(breakpointsMap_.value()); + } + + bool HasBreakpointsMap() const + { + return breakpointsMap_.has_value(); + } + +private: + NO_COPY_SEMANTIC(SaveAllPossibleBreakpointsParams); + NO_MOVE_SEMANTIC(SaveAllPossibleBreakpointsParams); + + std::optional>>> + breakpointsMap_ {}; +}; } // namespace panda::ecmascript::tooling #endif \ No newline at end of file diff --git a/tooling/base/pt_returns.h b/tooling/base/pt_returns.h index dea06ed9..d9dfa1ef 100644 --- a/tooling/base/pt_returns.h +++ b/tooling/base/pt_returns.h @@ -85,7 +85,7 @@ private: class GetPossibleAndSetBreakpointByUrlReturns : public PtBaseReturns { public: - explicit GetPossibleAndSetBreakpointByUrlReturns(std::vector> locations) + explicit GetPossibleAndSetBreakpointByUrlReturns(std::vector> locations) : locations_(std::move(locations)) {} ~GetPossibleAndSetBreakpointByUrlReturns() override = default; @@ -97,7 +97,7 @@ private: NO_COPY_SEMANTIC(GetPossibleAndSetBreakpointByUrlReturns); NO_MOVE_SEMANTIC(GetPossibleAndSetBreakpointByUrlReturns); - std::vector> locations_ {}; + std::vector> locations_ {}; }; class EvaluateOnCallFrameReturns : public PtBaseReturns { diff --git a/tooling/base/pt_script.h b/tooling/base/pt_script.h index d401881c..2d797e2b 100644 --- a/tooling/base/pt_script.h +++ b/tooling/base/pt_script.h @@ -102,6 +102,16 @@ public: endLine_ = endLine; } + std::vector> GetLocations() const + { + return locations_; + } + + void SetLocations(std::vector> locations) + { + locations_ = locations; + } + private: NO_COPY_SEMANTIC(PtScript); NO_MOVE_SEMANTIC(PtScript); @@ -113,6 +123,7 @@ private: std::string scriptSource_ {}; // js source code std::string sourceMapUrl_ {}; // source map url int32_t endLine_ {0}; // total line number of source file + std::vector> locations_ {}; }; } // namespace panda::ecmascript::tooling #endif diff --git a/tooling/base/pt_types.cpp b/tooling/base/pt_types.cpp index 73aab2f7..a161ce9a 100644 --- a/tooling/base/pt_types.cpp +++ b/tooling/base/pt_types.cpp @@ -3386,6 +3386,18 @@ std::unique_ptr BreakpointInfo::Create(const PtJson ¶ms) return paramsObject; } +std::shared_ptr BreakpointInfo::CreateAsSharedPtr(int32_t line, int32_t column, + std::string url, std::string condition) +{ + auto result = std::make_shared(); + result->lineNumber_ = line; + result->columnNumber_ = column; + result->url_ = url; + result->condition_ = condition; + + return result; +} + std::unique_ptr BreakpointInfo::ToJson() const { std::unique_ptr result = PtJson::CreateObject(); diff --git a/tooling/base/pt_types.h b/tooling/base/pt_types.h index 03a2b66b..39efb84e 100644 --- a/tooling/base/pt_types.h +++ b/tooling/base/pt_types.h @@ -100,6 +100,8 @@ public: ~BreakpointInfo() override = default; static std::unique_ptr Create(const PtJson ¶ms); + static std::shared_ptr CreateAsSharedPtr(int32_t line, int32_t column, + std::string url, std::string condition = ""); std::unique_ptr ToJson() const override; int32_t GetLineNumber() const @@ -173,6 +175,15 @@ private: std::optional restrictToFunction_ {}; }; +class HashBreakpointInfo { +public: + size_t operator()(const std::shared_ptr &bpoint) const + { + return (std::hash()(bpoint->GetUrl())) ^ + (std::hash()(bpoint->GetLineNumber())) ^ + (std::hash()(bpoint->GetColumnNumber())); + } +}; // Runtime.ScriptId using ScriptId = int32_t; diff --git a/tooling/client/domain/debugger_client.cpp b/tooling/client/domain/debugger_client.cpp index 1e21e836..7c5612e8 100644 --- a/tooling/client/domain/debugger_client.cpp +++ b/tooling/client/domain/debugger_client.cpp @@ -54,6 +54,8 @@ bool DebuggerClient::DispatcherCmd(const std::string &cmd) { "step-into", std::bind(&DebuggerClient::StepIntoCommand, this)}, { "step-out", std::bind(&DebuggerClient::StepOutCommand, this)}, { "step-over", std::bind(&DebuggerClient::StepOverCommand, this)}, + { "enable-launch-accelerate", std::bind(&DebuggerClient::EnableLaunchAccelerateCommand, this)}, + { "saveAllPossibleBreakpoints", std::bind(&DebuggerClient::SaveAllPossibleBreakpointsCommand, this)}, }; auto entry = dispatcherTable.find(cmd); @@ -433,4 +435,57 @@ void DebuggerClient::handleResponse(std::unique_ptr json) } return; } + +int DebuggerClient::SaveAllPossibleBreakpointsCommand() +{ + Session *session = SessionManager::getInstance().GetSessionById(sessionId_); + uint32_t id = session->GetMessageId(); + + std::unique_ptr request = PtJson::CreateObject(); + request->Add("id", id); + request->Add("method", "Debugger.saveAllPossibleBreakpoints"); + + std::unique_ptr params = PtJson::CreateObject(); + std::unique_ptr locations = PtJson::CreateObject(); + std::unique_ptr vector = PtJson::CreateArray(); + + std::unique_ptr bp = PtJson::CreateObject(); + bp->Add("lineNumber", breakPointInfoList_.back().lineNumber); + bp->Add("columnNumber", breakPointInfoList_.back().columnNumber); + vector->Push(bp); + locations->Add(breakPointInfoList_.back().url.c_str(), vector); + params->Add("locations", locations); + request->Add("params", params); + + std::string message = request->Stringify(); + if (session->ClientSendReq(message)) { + session->GetDomainManager().SetDomainById(id, "Debugger"); + } + + return 0; +} + +int DebuggerClient::EnableLaunchAccelerateCommand() +{ + Session *session = SessionManager::getInstance().GetSessionById(sessionId_); + uint32_t id = session->GetMessageId(); + + std::unique_ptr request = PtJson::CreateObject(); + request->Add("id", id); + request->Add("method", "Debugger.enable"); + + std::unique_ptr params = PtJson::CreateObject(); + std::unique_ptr options = PtJson::CreateArray(); + + options->Push("enableLaunchAccelerate"); + params->Add("options", options); + request->Add("params", params); + + std::string message = request->Stringify(); + if (session->ClientSendReq(message)) { + session->GetDomainManager().SetDomainById(id, "Debugger"); + } + + return 0; +} } // OHOS::ArkCompiler::Toolchain \ No newline at end of file diff --git a/tooling/client/domain/debugger_client.h b/tooling/client/domain/debugger_client.h index ddf03031..aaeffd40 100644 --- a/tooling/client/domain/debugger_client.h +++ b/tooling/client/domain/debugger_client.h @@ -59,6 +59,8 @@ public: int StepIntoCommand(); int StepOutCommand(); int StepOverCommand(); + int EnableLaunchAccelerateCommand(); + int SaveAllPossibleBreakpointsCommand(); void AddBreakPointInfo(const std::string& url, const int& lineNumber, const int& columnNumber = 0); void RecvReply(std::unique_ptr json); diff --git a/tooling/client/utils/cli_command.cpp b/tooling/client/utils/cli_command.cpp index 8fb86ac2..477a8287 100644 --- a/tooling/client/utils/cli_command.cpp +++ b/tooling/client/utils/cli_command.cpp @@ -182,6 +182,10 @@ void CliCommand::CreateCommandMap() {std::make_pair("enable", "enable"), std::bind(&CliCommand::DebuggerCommand, this, "enable")}, {std::make_pair("finish", "fin"), std::bind(&CliCommand::DebuggerCommand, this, "finish")}, {std::make_pair("frame", "f"), std::bind(&CliCommand::DebuggerCommand, this, "frame")}, + {std::make_pair("enable-launch-accelerate", "enable-acc"), + std::bind(&CliCommand::DebuggerCommand, this, "enable-launch-accelerate")}, + {std::make_pair("saveAllPossibleBreakpoints", "b-new"), + std::bind(&CliCommand::SaveAllPossibleBreakpointsCommand, this, "saveAllPossibleBreakpoints")}, }; CreateOtherCommandMap(); } @@ -622,6 +626,11 @@ ErrCode CliCommand::TestCommand(const std::string &cmd) return ErrCode::ERR_OK; } +ErrCode CliCommand::SaveAllPossibleBreakpointsCommand(const std::string &cmd) +{ + return BreakCommand(cmd); +} + ErrCode CliCommand::ExecHelpCommand() { std::cout << HELP_MSG; diff --git a/tooling/client/utils/cli_command.h b/tooling/client/utils/cli_command.h index 2720521d..88cafd29 100644 --- a/tooling/client/utils/cli_command.h +++ b/tooling/client/utils/cli_command.h @@ -72,6 +72,7 @@ public: ErrCode SessionSwitchCommand(const std::string &cmd); ErrCode TestCommand(const std::string &cmd); ErrCode ExecHelpCommand(); + ErrCode SaveAllPossibleBreakpointsCommand(const std::string &cmd); void OutputCommand(const std::string &cmd, bool flag); VecStr GetArgList() diff --git a/tooling/test/client_utils/test_list.cpp b/tooling/test/client_utils/test_list.cpp index cdd96ac0..233b6c48 100644 --- a/tooling/test/client_utils/test_list.cpp +++ b/tooling/test/client_utils/test_list.cpp @@ -70,6 +70,7 @@ #include "tooling/test/testcases/js_heapusage_loop_test.h" #include "tooling/test/testcases/js_heapusage_recursion_test.h" #include "tooling/test/testcases/js_smart_stepInto_test.h" +#include "tooling/test/testcases/js_accelerate_launch_test.h" namespace panda::ecmascript::tooling::test { static std::string g_currentTestName = ""; @@ -129,6 +130,7 @@ static void RegisterTests() TestUtil::RegisterTest("JsHeapusageLoopTest", GetJsHeapusageLoopTest()); TestUtil::RegisterTest("JsHeapusageRecursionTest", GetJsHeapusageRecursionTest()); TestUtil::RegisterTest("JsSmartStepoutTest", GetJsSmartStepoutTest()); + TestUtil::RegisterTest("JsAccelerateLaunchTest", GetJsAccelerateLaunchTest()); } std::vector GetTestList() diff --git a/tooling/test/debugger_impl_test.cpp b/tooling/test/debugger_impl_test.cpp index 0fbb8811..7d0e3654 100644 --- a/tooling/test/debugger_impl_test.cpp +++ b/tooling/test/debugger_impl_test.cpp @@ -194,6 +194,43 @@ HWTEST_F_L0(DebuggerImplTest, Dispatcher_Dispatch_Enable__002) } } +HWTEST_F_L0(DebuggerImplTest, Dispatcher_Dispatch_Enable_Accelerate_Launch_Mode) +{ + std::string outStrForCallbackCheck = ""; + std::function callback = + [&outStrForCallbackCheck]([[maybe_unused]] const void *ptr, const std::string &inStrOfReply) { + outStrForCallbackCheck = inStrOfReply;}; + ProtocolChannel *protocolChannel = new ProtocolHandler(callback, ecmaVm); + auto runtimeImpl = std::make_unique(ecmaVm, protocolChannel); + auto debuggerImpl = std::make_unique(ecmaVm, protocolChannel, runtimeImpl.get()); + auto dispatcherImpl = std::make_unique(protocolChannel, std::move(debuggerImpl)); + EXPECT_FALSE(ecmaVm->GetJsDebuggerManager()->IsDebugMode()); + + std::string msg = std::string() + + R"({ + "id":0, + "method":"Debugger.enable", + "params":{ + "maxScriptsCacheSize":1024, + "options":[ + "enableLaunchAccelerate" + ] + } + })"; + DispatchRequest request(msg); + dispatcherImpl->Dispatch(request); + + bool condition = outStrForCallbackCheck.find("protocols") != std::string::npos && + outStrForCallbackCheck.find("debuggerId") != std::string::npos && + outStrForCallbackCheck.find("saveAllPossibleBreakpoints") != std::string::npos; + EXPECT_TRUE(condition); + EXPECT_TRUE(ecmaVm->GetJsDebuggerManager()->IsDebugMode()); + if (protocolChannel) { + delete protocolChannel; + protocolChannel = nullptr; + } +} + HWTEST_F_L0(DebuggerImplTest, Dispatcher_Dispatch_Disable__001) { std::string outStrForCallbackCheck = ""; diff --git a/tooling/test/debugger_params_test.cpp b/tooling/test/debugger_params_test.cpp index 07877ed9..f01dcc53 100644 --- a/tooling/test/debugger_params_test.cpp +++ b/tooling/test/debugger_params_test.cpp @@ -224,6 +224,45 @@ HWTEST_F_L0(DebuggerParamsTest, EnableParamsCreateTest) EXPECT_EQ(enableParams->GetMaxScriptsCacheSize(), 100); } +HWTEST_F_L0(DebuggerParamsTest, EnableParamsAccelerateLaunchModeCreateTest) +{ + 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":{"options":["enableLaunchAccelerate"], "maxScriptsCacheSize":100}})"; + enableParams = EnableParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(enableParams, nullptr); + EXPECT_EQ(enableParams->GetMaxScriptsCacheSize(), 100); + EXPECT_EQ(enableParams->GetEnableOptionsList().size(), 1); +} + +HWTEST_F_L0(DebuggerParamsTest, SaveAllPossibleBreakpointsParamsCreateTest) +{ + std::string msg; + std::unique_ptr params; + + // abnormal + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{}})"; + params = SaveAllPossibleBreakpointsParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_EQ(params, nullptr); + + // normal + msg = std::string() + R"({"id":0,"method":"Debugger.Test","params":{ + "locations":{"actualUrl/actualFileName.ts":[{"lineNumber": 7, "columnNumber": 8}]}}})"; + params = SaveAllPossibleBreakpointsParams::Create(DispatchRequest(msg).GetParams()); + ASSERT_NE(params, nullptr); + EXPECT_TRUE(params->HasBreakpointsMap()); + EXPECT_EQ(params->GetBreakpointsMap()->size(), 1); +} + HWTEST_F_L0(DebuggerParamsTest, StartSamplingParamsCreateTest) { std::string msg; diff --git a/tooling/test/debugger_returns_test.cpp b/tooling/test/debugger_returns_test.cpp index 28062b6b..abe1dfd4 100644 --- a/tooling/test/debugger_returns_test.cpp +++ b/tooling/test/debugger_returns_test.cpp @@ -417,12 +417,12 @@ HWTEST_F_L0(DebuggerReturnsTest, SearchInContentReturnsToJsonTest) HWTEST_F_L0(DebuggerReturnsTest, GetPossibleAndSetBreakpointByUrlReturnsToJsonTest) { - auto locations = std::vector>(); - std::unique_ptr breakpointReturnInfo = std::make_unique(); + auto locations = std::vector>(); + std::shared_ptr breakpointReturnInfo = std::make_shared(); breakpointReturnInfo->SetScriptId(11).SetLineNumber(1).SetColumnNumber(44); - locations.emplace_back(std::move(breakpointReturnInfo)); + locations.emplace_back(breakpointReturnInfo); std::unique_ptr getPossibleAndSetBreakpointByUrlReturns = std::make_unique - (std::move(locations)); + (locations); std::unique_ptr locationsJS; ASSERT_EQ(getPossibleAndSetBreakpointByUrlReturns->ToJson()->GetArray("locations", &locationsJS), Result::SUCCESS); ASSERT_NE(locationsJS, nullptr); diff --git a/tooling/test/debugger_script_test.cpp b/tooling/test/debugger_script_test.cpp index ce1492c3..38562947 100644 --- a/tooling/test/debugger_script_test.cpp +++ b/tooling/test/debugger_script_test.cpp @@ -106,4 +106,16 @@ HWTEST_F_L0(DebuggerScriptTest, EndLineTest) script->SetEndLine(200); ASSERT_EQ(script->GetEndLine(), 200); } + +HWTEST_F_L0(DebuggerScriptTest, LocationsTest) +{ + std::unique_ptr script = std::make_unique(1, "name_1", "url_1", "source_1"); + std::vector> locations {}; + std::shared_ptr bpInfo = std::make_shared(); + std::string invalidBpId = "invalid"; + bpInfo->SetId(invalidBpId).SetLineNumber(1).SetColumnNumber(0); + locations.emplace_back(bpInfo); + script->SetLocations(locations); + ASSERT_EQ(script->GetLocations().size(), 1); +} } // namespace panda::test \ No newline at end of file diff --git a/tooling/test/pt_json_test.cpp b/tooling/test/pt_json_test.cpp index 9f42e46a..c128aedb 100644 --- a/tooling/test/pt_json_test.cpp +++ b/tooling/test/pt_json_test.cpp @@ -313,4 +313,15 @@ HWTEST_F_L0(PtJsonTest, ResultUInt64Test) ASSERT_EQ(test->GetUInt64("b", &ui64), Result::SUCCESS); EXPECT_EQ(ui64, static_cast(100)); } + +HWTEST_F_L0(PtJsonTest, GetKeysArraytest) +{ + auto test = PtJson::CreateObject(); + test->Add("a", "ResultUInt64Test"); + test->Add("b", 100); + auto keys = test->GetKeysArray(); + EXPECT_EQ(keys.size(), 2); + EXPECT_TRUE(keys.at(0) == "a"); + EXPECT_TRUE(keys.at(1) == "b"); +} } \ No newline at end of file diff --git a/tooling/test/testcases/js_accelerate_launch_test.h b/tooling/test/testcases/js_accelerate_launch_test.h new file mode 100644 index 00000000..45366e4a --- /dev/null +++ b/tooling/test/testcases/js_accelerate_launch_test.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2023 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_TESTCASES_JS_ACCELERATE_LAUNCH_TEST_H +#define ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_ACCELERATE_LAUNCH_TEST_H + +#include "tooling/test/client_utils/test_util.h" + +namespace panda::ecmascript::tooling::test { +class JsAccelerateLaunchTest : public TestActions { +public: + JsAccelerateLaunchTest() + { + testAction = { + // Enable Accelerate Launch Mode + {SocketAction::SEND, "enable-acc"}, + {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess}, + {SocketAction::SEND, "runtime-enable"}, + {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess}, + // Debugger.saveAllPossibleBreakpoints + {SocketAction::SEND, "b-new " DEBUGGER_JS_DIR "sample.js 22"}, + {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess}, + {SocketAction::SEND, "run"}, + {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess}, + // load sample.js + {SocketAction::RECV, "Debugger.scriptParsed", ActionRule::STRING_CONTAIN}, + {SocketAction::RECV, "Debugger.paused", ActionRule::STRING_CONTAIN}, + {SocketAction::SEND, "resume"}, + {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN}, + {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess}, + {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE, [this] (auto recv, auto, auto) -> bool { + std::unique_ptr json = PtJson::Parse(recv); + Result ret; + std::string method; + ret = json->GetString("method", &method); + if (ret != Result::SUCCESS || method != "Debugger.paused") { + return false; + } + + std::unique_ptr params = nullptr; + ret = json->GetObject("params", ¶ms); + if (ret != Result::SUCCESS) { + return false; + } + + std::unique_ptr hitBreakpoints = nullptr; + ret = params->GetArray("hitBreakpoints", &hitBreakpoints); + if (ret != Result::SUCCESS) { + return false; + } + + std::string breakpoint; + breakpoint = hitBreakpoints->Get(0)->GetString(); + if (ret != Result::SUCCESS || breakpoint.find(sourceFile_) == std::string::npos || + breakpoint.find("21") == std::string::npos) { + return false; + } + return true; + }}, + {SocketAction::SEND, "b " DEBUGGER_JS_DIR "sample.js 23"}, + {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess}, + {SocketAction::SEND, "resume"}, + {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN}, + {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess}, + {SocketAction::RECV, "Debugger.paused", ActionRule::CUSTOM_RULE, [this] (auto recv, auto, auto) -> bool { + std::unique_ptr json = PtJson::Parse(recv); + Result ret; + std::string method; + ret = json->GetString("method", &method); + if (ret != Result::SUCCESS || method != "Debugger.paused") { + return false; + } + + std::unique_ptr params = nullptr; + ret = json->GetObject("params", ¶ms); + if (ret != Result::SUCCESS) { + return false; + } + + std::unique_ptr hitBreakpoints = nullptr; + ret = params->GetArray("hitBreakpoints", &hitBreakpoints); + if (ret != Result::SUCCESS) { + return false; + } + + std::string breakpoint; + breakpoint = hitBreakpoints->Get(0)->GetString(); + if (ret != Result::SUCCESS || breakpoint.find(sourceFile_) == std::string::npos || + breakpoint.find("22") == std::string::npos) { + return false; + } + return true; + }}, + {SocketAction::SEND, "success"}, + {SocketAction::SEND, "resume"}, + {SocketAction::RECV, "Debugger.resumed", ActionRule::STRING_CONTAIN}, + {SocketAction::RECV, "", ActionRule::CUSTOM_RULE, MatchRule::replySuccess}, + }; + } + + std::pair GetEntryPoint() override + { + return {pandaFile_, entryPoint_}; + } + ~JsAccelerateLaunchTest() = default; + +private: + std::string pandaFile_ = DEBUGGER_ABC_DIR "sample.abc"; + std::string sourceFile_ = DEBUGGER_JS_DIR "sample.js"; + std::string entryPoint_ = "_GLOBAL::func_main_0"; +}; + +std::unique_ptr GetJsAccelerateLaunchTest() +{ + return std::make_unique(); +} +} // namespace panda::ecmascript::tooling::test + +#endif // ECMASCRIPT_TOOLING_TEST_TESTCASES_JS_ACCELERATE_LAUNCH_TEST_H diff --git a/tooling/test/utils/test_hooks.h b/tooling/test/utils/test_hooks.h index 88cda04a..1fd7e2bd 100644 --- a/tooling/test/utils/test_hooks.h +++ b/tooling/test/utils/test_hooks.h @@ -118,6 +118,8 @@ public: void SendableMethodEntry([[maybe_unused]] JSHandle method) override {} + void DisableFirstTimeFlag() override {} + void TerminateTest() { debugInterface_->UnregisterHooks(); -- Gitee From 56190d2e209a32e3cb9e814838dad9ff38942d67 Mon Sep 17 00:00:00 2001 From: fangting Date: Mon, 9 Dec 2024 15:29:01 +0800 Subject: [PATCH 2/2] fix url error Issue:#IB9XC2 Signed-off-by: fangting --- tooling/agent/debugger_impl.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tooling/agent/debugger_impl.cpp b/tooling/agent/debugger_impl.cpp index 9428bac8..30083978 100755 --- a/tooling/agent/debugger_impl.cpp +++ b/tooling/agent/debugger_impl.cpp @@ -88,6 +88,11 @@ bool DebuggerImpl::NotifyScriptParsed(const std::string &fileName, std::string_v return false; } + if (!vm_->GetJsDebuggerManager()->GetFaApp() && jsPandaFile->IsBundlePack()) { + LOG_DEBUGGER(DEBUG) << "NotifyScriptParsed: Unmerge file: " << fileName; + return false; + } + const char *recordName = entryPoint.data(); auto mainMethodIndex = panda_file::File::EntityId(jsPandaFile->GetMainMethodIndex(recordName)); const std::string &source = extractor->GetSourceCode(mainMethodIndex); -- Gitee