From 3b6ea985b02dc7a12d9eb8ee2da4a4c9b5dade57 Mon Sep 17 00:00:00 2001 From: Nicolas Chevobbe Date: Tue, 9 Nov 2021 14:37:43 +0000 Subject: [PATCH] Bug 1739990 - Fix perf regression in getInScopeLines. r=jdescottes. The patch for Bug 1737993 did a very readable but not performant replacement of lodash `without` usage in `getInScopeLines`. This patch changes things a bit so we get a similar level of performance as what we had before, when using `without`. For this we : - make `getOutOfScopeLines` returns a `Set` so checking inclusion is faster - create the final array of "in scope lines" using a for loop and assigning line number when needed, and then filtering out empty slots. Differential Revision: https://phabricator.services.mozilla.com/D130742 --- .../src/actions/ast/setInScopeLines.js | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/devtools/client/debugger/src/actions/ast/setInScopeLines.js b/devtools/client/debugger/src/actions/ast/setInScopeLines.js index 210dded563cd..87c7065cb5a2 100644 --- a/devtools/client/debugger/src/actions/ast/setInScopeLines.js +++ b/devtools/client/debugger/src/actions/ast/setInScopeLines.js @@ -10,7 +10,6 @@ import { import { getSourceLineCount } from "../../utils/source"; -import { range, flatMap, uniq } from "lodash"; import { isFulfilled } from "../../utils/async-value"; function getOutOfScopeLines(outOfScopeLocations) { @@ -18,11 +17,14 @@ function getOutOfScopeLines(outOfScopeLocations) { return null; } - return uniq( - flatMap(outOfScopeLocations, location => - range(location.start.line, location.end.line) - ) - ); + const uniqueLines = new Set(); + for (const location of outOfScopeLocations) { + for (let i = location.start.line; i < location.end.line; i++) { + uniqueLines.add(i); + } + } + + return uniqueLines; } async function getInScopeLines(cx, location, { dispatch, getState, parser }) { @@ -39,11 +41,25 @@ async function getInScopeLines(cx, location, { dispatch, getState, parser }) { ? 0 : getSourceLineCount(source.content.value); - const sourceLines = range(1, sourceNumLines + 1); + const noLinesOutOfScope = + linesOutOfScope == null || linesOutOfScope.size == 0; - return !linesOutOfScope - ? sourceLines - : sourceLines.filter(sourceLine => !linesOutOfScope.includes(sourceLine)); + // This operation can be very costly for large files so we sacrifice a bit of readability + // for performance sake. + // We initialize an array with a fixed size and we'll directly assign value for lines + // that are not out of scope. This is much faster than having an empty array and pushing + // into it. + const sourceLines = new Array(sourceNumLines); + for (let i = 0; i < sourceNumLines; i++) { + const line = i + 1; + if (noLinesOutOfScope || !linesOutOfScope.has(line)) { + sourceLines[i] = line; + } + } + + // Finally we need to remove any undefined values, i.e. the ones that were matching + // out of scope lines. + return sourceLines.filter(i => i != undefined); } export function setInScopeLines(cx) {