# UNDF: UNDF-2026-000000809 # UNDF: (leave blank) # vscode-0003: userDataSync merge compare() functions O(N×M) array includes # # Files affected (all same pattern): # src/vs/platform/userDataSync/common/extensionsMerge.ts (lines 259-260, 375-376) # src/vs/platform/userDataSync/common/settingsMerge.ts (lines 301-302) # src/vs/platform/userDataSync/common/globalStateMerge.ts (lines 126-127) # src/vs/platform/userDataSync/common/snippetsMerge.ts (lines 156-157) # src/vs/platform/userDataSync/common/keybindingsMerge.ts (lines 258-259, 279-280) # src/vs/platform/userDataSync/common/promptsSync/promptsMerge.ts (lines 156-157) # src/vs/platform/userDataSync/common/userDataProfilesManifestMerge.ts (lines 118-119) # # Defect: Every compare() function computes set-difference between two key # arrays using fromKeys.filter(key => !toKeys.includes(key)) — O(N×M) # where N, M = number of keys in each side. Runs on every sync merge. # Fix: Convert one side to a Set before filtering. The result is already # fed into a Set, so intermediate Set creation is free. # Severity: MEDIUM (N = settings/extensions/keybindings count, 100-500) # Speedup: 250x at N=500 # # Representative fix for extensionsMerge.ts compare(): --- a/src/vs/platform/userDataSync/common/extensionsMerge.ts +++ b/src/vs/platform/userDataSync/common/extensionsMerge.ts @@ -256,8 +256,10 @@ function compare(from: Map | null, to: Map, ignoredExtensions: Set, checkVersionProperty: boolean): { added: Set; removed: Set; updated: Set } { const fromKeys = from ? [...from.keys()].filter(key => !ignoredExtensions.has(key)) : []; const toKeys = [...to.keys()].filter(key => !ignoredExtensions.has(key)); - const added = toKeys.filter(key => !fromKeys.includes(key)).reduce((r, key) => { r.add(key); return r; }, new Set()); - const removed = fromKeys.filter(key => !toKeys.includes(key)).reduce((r, key) => { r.add(key); return r; }, new Set()); + const fromKeysSet = new Set(fromKeys); + const toKeysSet = new Set(toKeys); + const added = toKeys.filter(key => !fromKeysSet.has(key)).reduce((r, key) => { r.add(key); return r; }, new Set()); + const removed = fromKeys.filter(key => !toKeysSet.has(key)).reduce((r, key) => { r.add(key); return r; }, new Set()); const updated: Set = new Set(); # Same fix applies to all 7 other compare() call sites listed above. # Each instance: replace array.includes() with Set.has() by converting # the lookup array to a Set before the filter call.