From 2fa104f73a78890162186a87708110e3eec33d1a Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Thu, 29 Mar 2018 14:43:01 +0200 Subject: [PATCH] avoid walking scopes multiple times for performance reasons --- lib/optimize/ConcatenatedModule.js | 82 +++++++++++++++---- .../scope-hoisting/renaming-4967/file1.js | 10 +++ 2 files changed, 74 insertions(+), 18 deletions(-) diff --git a/lib/optimize/ConcatenatedModule.js b/lib/optimize/ConcatenatedModule.js index 3a19195ab..480f22759 100644 --- a/lib/optimize/ConcatenatedModule.js +++ b/lib/optimize/ConcatenatedModule.js @@ -168,17 +168,29 @@ const getFinalName = ( } }; -const getSymbolsFromScope = (s, untilScope) => { - const allUsedNames = new Set(); +const addScopeSymbols1 = (s, nameSet, scopeSet) => { let scope = s; while (scope) { + if (scopeSet.has(scope)) break; + scopeSet.add(scope); for (const variable of scope.variables) { - allUsedNames.add(variable.name); + nameSet.add(variable.name); + } + scope = scope.upper; + } +}; + +const addScopeSymbols2 = (s, nameSet, scopeSet1, scopeSet2) => { + let scope = s; + while (scope) { + if (scopeSet1.has(scope)) break; + if (scopeSet2.has(scope)) break; + scopeSet1.add(scope); + for (const variable of scope.variables) { + nameSet.add(variable.name); } - if (untilScope === scope) break; scope = scope.upper; } - return allUsedNames; }; const getAllReferences = variable => { @@ -196,11 +208,6 @@ const getAllReferences = variable => { return set; }; -const reduceSet = (a, b) => { - for (const item of b) a.add(item); - return a; -}; - const getPathInAst = (ast, node) => { if (ast === node) { return []; @@ -816,8 +823,31 @@ class ConcatenatedModule extends Module { "onsubmit" ]); + // Set of already checked scopes + const alreadyCheckedScopes = new Set(); + // get all global names for (const info of modulesWithInfo) { + const superClassExpressions = []; + + // ignore symbols from moduleScope + if (info.moduleScope) { + alreadyCheckedScopes.add(info.moduleScope); + + // The super class expression in class scopes behaves weird + // We store ranges of all super class expressions to make + // renaming to work correctly + for (const childScope of info.moduleScope.childScopes) { + if (childScope.type !== "class") continue; + if (!childScope.block.superClass) continue; + superClassExpressions.push({ + range: childScope.block.superClass.range, + variables: childScope.variables + }); + } + } + + // add global symbols if (info.globalScope) { for (const reference of info.globalScope.through) { const name = reference.identifier.name; @@ -826,12 +856,21 @@ class ConcatenatedModule extends Module { name ) ) { - for (const s of getSymbolsFromScope( - reference.from, - info.moduleScope - )) { - allUsedNames.add(s); + for (const expr of superClassExpressions) { + if ( + expr.range[0] <= reference.identifier.range[0] && + expr.range[1] >= reference.identifier.range[1] + ) { + for (const variable of expr.variables) { + allUsedNames.add(variable.name); + } + } } + addScopeSymbols1( + reference.from, + allUsedNames, + alreadyCheckedScopes + ); } else { allUsedNames.add(name); } @@ -856,9 +895,16 @@ class ConcatenatedModule extends Module { const name = variable.name; if (allUsedNames.has(name)) { const references = getAllReferences(variable); - const symbolsInReferences = references - .map(ref => getSymbolsFromScope(ref.from, info.moduleScope)) - .reduce(reduceSet, new Set()); + const symbolsInReferences = new Set(); + const alreadyCheckedInnerScopes = new Set(); + for (const ref of references) { + addScopeSymbols2( + ref.from, + symbolsInReferences, + alreadyCheckedInnerScopes, + alreadyCheckedScopes + ); + } const newName = this.findNewName( name, allUsedNames, diff --git a/test/cases/scope-hoisting/renaming-4967/file1.js b/test/cases/scope-hoisting/renaming-4967/file1.js index 952255b8c..d38cc0947 100644 --- a/test/cases/scope-hoisting/renaming-4967/file1.js +++ b/test/cases/scope-hoisting/renaming-4967/file1.js @@ -6,5 +6,15 @@ export function test() { function file1_js_a() { return "fail"; } + function file1_a() { + return "fail"; + } return a(); } + +function renaming_4967_file1_js_a() { + return "fail"; +} +function renaming_4967_file1_a() { + return "fail"; +}