diff --git a/Nodejs/Product/Analysis/Analysis/Analyzer/AnalysisUnit.cs b/Nodejs/Product/Analysis/Analysis/Analyzer/AnalysisUnit.cs index 7cf38ec99..d7ad94cfe 100644 --- a/Nodejs/Product/Analysis/Analysis/Analyzer/AnalysisUnit.cs +++ b/Nodejs/Product/Analysis/Analysis/Analyzer/AnalysisUnit.cs @@ -32,6 +32,9 @@ namespace Microsoft.NodejsTools.Analysis { /// Our dependency tracking scheme works by tracking analysis units - when we add a dependency it is the current /// AnalysisUnit which is dependent upon the variable. If the value of a variable changes then all of the dependent /// AnalysisUnit's will be re-enqueued. This proceeds until we reach a fixed point. + /// + /// Note that AnalysisUnit contructors / methods are not threadsafe because we expect there to be many AnalysisUnits, + /// and we want to keep things as performant as possible (which means minimizing locking behavior and whatnot.) /// [Serializable] internal class AnalysisUnit : ISet { diff --git a/Nodejs/Product/Analysis/Analysis/JsAnalyzer.cs b/Nodejs/Product/Analysis/Analysis/JsAnalyzer.cs index c45144e58..f8a2eecef 100644 --- a/Nodejs/Product/Analysis/Analysis/JsAnalyzer.cs +++ b/Nodejs/Product/Analysis/Analysis/JsAnalyzer.cs @@ -143,15 +143,12 @@ public IAnalyzable AddPackageJson(string filePath, string entryPoint, List(); + ProjectEntry projectEntry = null; if (dependencies != null) { - var projectEntry = new ProjectEntry(this, filePath, null); - requireAnalysisUnits.AddRange(dependencies.Select( - dependency => { return new RequireAnalysisUnit(tree, Modules, projectEntry, dependency); - })); + projectEntry = new ProjectEntry(this, filePath, null); } - return new TreeUpdateAnalysis(tree, requireAnalysisUnits); + return new TreeUpdateAnalysis(tree, dependencies, projectEntry, Modules); } /// @@ -162,22 +159,33 @@ public IAnalyzable AddPackageJson(string filePath, string entryPoint, List _requireAnalysisUnits; + private readonly IEnumerable _dependencies; + private readonly ProjectEntry _projectEntry; + private readonly ModuleTable _modules; - public TreeUpdateAnalysis(ModuleTree tree, IEnumerable requireAnalysisUnits = null) { + public TreeUpdateAnalysis(ModuleTree tree, IEnumerable dependencies = null, ProjectEntry projectEntry = null, ModuleTable modules = null) { _tree = tree; - _requireAnalysisUnits = requireAnalysisUnits; + _dependencies = dependencies; + _projectEntry = projectEntry; + _modules = modules; } public void Analyze(CancellationToken cancel) { if (_tree != null) { _tree.EnqueueDependents(); } - if (_requireAnalysisUnits != null) { - foreach (var unit in _requireAnalysisUnits) { + + if (_dependencies != null) { + var requireAnalysisUnits = new List(); + requireAnalysisUnits.AddRange(_dependencies.Select( + dependency => { + return new RequireAnalysisUnit(_tree, _modules, _projectEntry, dependency); + })); + + foreach (var unit in requireAnalysisUnits) { unit.AnalyzeWorker(null, cancel); } - } + } } }