From a4d4363060192b58ec6076b46065212153061192 Mon Sep 17 00:00:00 2001 From: Markus Stange Date: Mon, 11 Aug 2025 12:47:41 -0400 Subject: [PATCH] Remove recursion in filterThreadToSearchString. --- src/profile-logic/profile-data.ts | 46 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/src/profile-logic/profile-data.ts b/src/profile-logic/profile-data.ts index db9a3fbbe7..e902d3c5ac 100644 --- a/src/profile-logic/profile-data.ts +++ b/src/profile-logic/profile-data.ts @@ -25,7 +25,7 @@ import { } from 'firefox-profiler/app-logic/constants'; import { timeCode } from 'firefox-profiler/utils/time-code'; import { bisectionRight, bisectionLeft } from 'firefox-profiler/utils/bisect'; -import { makeBitSet } from 'firefox-profiler/utils/bitset'; +import { checkBit, makeBitSet, setBit } from 'firefox-profiler/utils/bitset'; import { parseFileNameFromSymbolication } from 'firefox-profiler/utils/special-paths'; import { StringTable } from 'firefox-profiler/utils/string-table'; import { @@ -1507,7 +1507,7 @@ export function filterThreadToSearchString( const { funcTable, frameTable, stackTable, stringTable, resourceTable } = thread; - function computeFuncMatchesFilter(func: IndexIntoFuncTable) { + function computeFuncMatchesSearch(func: IndexIntoFuncTable) { const nameIndex = funcTable.name[func]; const nameString = stringTable.getString(nameIndex); if (nameString.toLowerCase().includes(lowercaseSearchString)) { @@ -1534,38 +1534,32 @@ export function filterThreadToSearchString( return false; } - const funcMatchesFilterCache = new Map(); - function funcMatchesFilter(func: IndexIntoFuncTable) { - let result = funcMatchesFilterCache.get(func); - if (result === undefined) { - result = computeFuncMatchesFilter(func); - funcMatchesFilterCache.set(func, result); + const funcMatchesSearch = makeBitSet(funcTable.length); + for (let funcIndex = 0; funcIndex < funcTable.length; funcIndex++) { + if (computeFuncMatchesSearch(funcIndex)) { + setBit(funcMatchesSearch, funcIndex); } - return result; } - const stackMatchesFilterCache = new Map(); - function stackMatchesFilter(stackIndex: IndexIntoStackTable | null) { - if (stackIndex === null) { - return false; - } - let result = stackMatchesFilterCache.get(stackIndex); - if (result === undefined) { - const prefix = stackTable.prefix[stackIndex]; - if (stackMatchesFilter(prefix)) { - result = true; - } else { - const frame = stackTable.frame[stackIndex]; - const func = frameTable.func[frame]; - result = funcMatchesFilter(func); + const stackMatchesSearch = makeBitSet(funcTable.length); + for (let stackIndex = 0; stackIndex < stackTable.length; stackIndex++) { + const prefix = stackTable.prefix[stackIndex]; + if (prefix !== null && checkBit(stackMatchesSearch, prefix)) { + setBit(stackMatchesSearch, stackIndex); + } else { + const funcIndex = frameTable.func[stackTable.frame[stackIndex]]; + if (checkBit(funcMatchesSearch, funcIndex)) { + setBit(stackMatchesSearch, stackIndex); } - stackMatchesFilterCache.set(stackIndex, result); } - return result; } + // Set any stacks which don't include the search string to null. + // TODO: This includes stacks in markers; maybe we shouldn't clear marker stacks? return updateThreadStacks(thread, stackTable, (stackIndex) => - stackMatchesFilter(stackIndex) ? stackIndex : null + stackIndex !== null && checkBit(stackMatchesSearch, stackIndex) + ? stackIndex + : null ); }