diff --git a/src/jsifier.mjs b/src/jsifier.mjs index 83fa44163cf00..70f1b1a46cad6 100644 --- a/src/jsifier.mjs +++ b/src/jsifier.mjs @@ -127,27 +127,40 @@ function isDefined(symName) { return false; } +const transitiveDepsCache = new Map(); + function getTransitiveDeps(symbol) { - // TODO(sbc): Use some kind of cache to avoid quadratic behaviour here. + let result = transitiveDepsCache.get(symbol); + if (result) { + return result; + } const transitiveDeps = new Set(); const seen = new Set(); const toVisit = [symbol]; while (toVisit.length) { const sym = toVisit.pop(); if (!seen.has(sym)) { - let directDeps = LibraryManager.library[sym + '__deps'] ?? []; - directDeps = directDeps.filter((d) => typeof d === 'string'); - for (const dep of directDeps) { + const cached = transitiveDepsCache.get(sym); + let deps = cached; + if (!deps) { + deps = LibraryManager.library[sym + '__deps'] ?? []; + deps = deps.filter((d) => typeof d === 'string'); + } + for (const dep of deps) { if (!transitiveDeps.has(dep)) { debugLog(`adding dependency ${symbol} -> ${dep}`); + transitiveDeps.add(dep); + if (!cached) { + toVisit.push(dep); + } } - transitiveDeps.add(dep); - toVisit.push(dep); } seen.add(sym); } } - return Array.from(transitiveDeps); + result = Array.from(transitiveDeps); + transitiveDepsCache.set(symbol, result); + return result; } function shouldPreprocess(fileName) { @@ -413,9 +426,9 @@ const PROXY_SYNC = 1; const PROXY_SYNC_ASYNC = 2; export async function runJSify(outputFile, symbolsOnly) { + transitiveDepsCache.clear(); const libraryItems = []; const libraryAliases = []; - const symbolDeps = {}; const asyncFuncs = []; let postSets = []; @@ -629,13 +642,6 @@ function(${args}) { } if (symbolsOnly) { - if (LibraryManager.library.hasOwnProperty(symbol)) { - // Resolve aliases before looking up deps - var transitiveDeps = getTransitiveDeps(symbol); - symbolDeps[symbol] = transitiveDeps.filter( - (d) => !isJsOnlySymbol(d) && !(d in LibraryManager.library), - ); - } return; } @@ -1003,6 +1009,15 @@ var proxiedFunctionTable = [ timer.stop('symbolHandler'); if (symbolsOnly) { + const symbolDeps = {}; + for (const sym of Object.keys(LibraryManager.library)) { + if (!isDecorator(sym)) { + const transitiveDeps = getTransitiveDeps(sym); + symbolDeps[sym] = transitiveDeps.filter( + (d) => !isJsOnlySymbol(d) && !(d in LibraryManager.library), + ); + } + } writeOutput( JSON.stringify({ deps: symbolDeps,