From 4ba34b038cf9f27fa1d239555df8b09fa9d52675 Mon Sep 17 00:00:00 2001 From: shuppy Date: Thu, 21 Aug 2025 19:00:32 +0800 Subject: [PATCH] devtools: Fix available breakpoint positions with nested scripts (#38826) in the [SpiderMonkey Debugger API](https://firefox-source-docs.mozilla.org/js/Debugger/), there is a separate [Debugger.Script](https://firefox-source-docs.mozilla.org/js/Debugger/Debugger.Script.html) object for each function in a script, forming a tree of Script objects. since we were only issuing [getPossibleBreakpoints()](https://firefox-source-docs.mozilla.org/js/Debugger/Debugger.Script.html#getpossiblebreakpoints-query) queries to the [root Script object](https://firefox-source-docs.mozilla.org/js/Debugger/Debugger.html#onnewscript-script-global) for each script, we were failing to report locations inside functions as available for setting breakpoints. this patch fixes that by recursively issuing the getPossibleBreakpoints() requests over the [getChildScripts()](https://firefox-source-docs.mozilla.org/js/Debugger/Debugger.Script.html#getchildscripts) tree. Testing: this patch adds a new devtools test Signed-off-by: Delan Azabani Co-authored-by: atbrakhi --- python/servo/devtools_tests.py | 16 ++++++++++++++++ .../test_with_functions.html | 10 ++++++++++ resources/debugger.js | 12 +++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 python/servo/devtools_tests/sources_breakable_lines_and_positions/test_with_functions.html diff --git a/python/servo/devtools_tests.py b/python/servo/devtools_tests.py index c1043ce42df..0afd38e2b4b 100644 --- a/python/servo/devtools_tests.py +++ b/python/servo/devtools_tests.py @@ -599,6 +599,22 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): }, ) + def test_source_breakable_lines_and_positions_with_functions(self): + self.start_web_server(test_dir=self.get_test_path("sources_breakable_lines_and_positions")) + self.run_servoshell(url=f"{self.base_urls[0]}/test_with_functions.html") + self.assert_source_breakable_lines_and_positions( + Source("inlineScript", f"{self.base_urls[0]}/test_with_functions.html"), + [5, 6, 7, 8, 9, 10], + { + "5": [8, 18], + "6": [12], + "7": [8], + "8": [4], + "9": [4], + "10": [0], + }, + ) + # Sets `base_url` and `web_server` and `web_server_thread`. def start_web_server(self, *, test_dir=None, num_servers=2): assert self.base_urls is None and self.web_servers is None and self.web_server_threads is None diff --git a/python/servo/devtools_tests/sources_breakable_lines_and_positions/test_with_functions.html b/python/servo/devtools_tests/sources_breakable_lines_and_positions/test_with_functions.html new file mode 100644 index 00000000000..6eac193c50a --- /dev/null +++ b/python/servo/devtools_tests/sources_breakable_lines_and_positions/test_with_functions.html @@ -0,0 +1,10 @@ + + + diff --git a/resources/debugger.js b/resources/debugger.js index 90ab4715989..5019749db17 100644 --- a/resources/debugger.js +++ b/resources/debugger.js @@ -38,5 +38,15 @@ addEventListener("addDebuggee", event => { addEventListener("getPossibleBreakpoints", event => { const {spidermonkeyId} = event; - getPossibleBreakpointsResult(event, sourceIdsToScripts.get(spidermonkeyId).getPossibleBreakpoints(/* TODO: `query` */)); + const script = sourceIdsToScripts.get(spidermonkeyId); + function getPossibleBreakpointsRecursive(script) { + const result = script.getPossibleBreakpoints(/* TODO: `query` */); + for (const child of script.getChildScripts()) { + for (const location of getPossibleBreakpointsRecursive(child)) { + result.push(location); + } + } + return result; + } + getPossibleBreakpointsResult(event, getPossibleBreakpointsRecursive(script)); });