Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(259)

Side by Side Diff: lib/src/compiler.dart

Issue 1376123004: Batch the batch compiler for tests (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Address comments Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/checker/checker.dart ('k') | test/codegen/expect/DeltaBlue.txt » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 /// Command line tool to run the checker on a Dart program. 5 /// Command line tool to run the checker on a Dart program.
6 library dev_compiler.src.compiler; 6 library dev_compiler.src.compiler;
7 7
8 import 'dart:async'; 8 import 'dart:async';
9 import 'dart:collection'; 9 import 'dart:collection';
10 import 'dart:math' as math; 10 import 'dart:math' as math;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
64 } 64 }
65 65
66 bool compile(CompilerOptions options) { 66 bool compile(CompilerOptions options) {
67 assert(!options.serverMode); 67 assert(!options.serverMode);
68 var context = createAnalysisContextWithSources( 68 var context = createAnalysisContextWithSources(
69 options.strongOptions, options.sourceOptions); 69 options.strongOptions, options.sourceOptions);
70 var reporter = createErrorReporter(context, options); 70 var reporter = createErrorReporter(context, options);
71 return new BatchCompiler(context, options, reporter: reporter).run(); 71 return new BatchCompiler(context, options, reporter: reporter).run();
72 } 72 }
73 73
74 // Callback on each individual compiled library
75 typedef void CompilationNotifier(String path);
76
74 class BatchCompiler extends AbstractCompiler { 77 class BatchCompiler extends AbstractCompiler {
75 JSGenerator _jsGen; 78 JSGenerator _jsGen;
76 LibraryElement _dartCore; 79 LibraryElement _dartCore;
77 String _runtimeOutputDir; 80 String _runtimeOutputDir;
78 81
79 /// Already compiled sources, so we don't compile them again. 82 /// Already compiled sources, so we don't check or compile them again.
80 final _compiled = new HashSet<LibraryElement>(); 83 final _compilationRecord = <LibraryElement, bool>{};
81 bool _sdkCopied = false; 84 bool _sdkCopied = false;
82 85
83 bool _failure = false; 86 bool _failure = false;
84 bool get failure => _failure; 87 bool get failure => _failure;
85 88
89 final _pendingLibraries = <LibraryUnit>[];
90
86 BatchCompiler(AnalysisContext context, CompilerOptions options, 91 BatchCompiler(AnalysisContext context, CompilerOptions options,
87 {AnalysisErrorListener reporter}) 92 {AnalysisErrorListener reporter})
88 : super( 93 : super(
89 context, 94 context,
90 options, 95 options,
91 new ErrorCollector( 96 new ErrorCollector(
92 reporter ?? AnalysisErrorListener.NULL_LISTENER)) { 97 reporter ?? AnalysisErrorListener.NULL_LISTENER)) {
93 _inputBaseDir = options.inputBaseDir; 98 _inputBaseDir = options.inputBaseDir;
94 if (outputDir != null) { 99 if (outputDir != null) {
95 _jsGen = new JSGenerator(this); 100 _jsGen = new JSGenerator(this);
96 _runtimeOutputDir = path.join(outputDir, 'dev_compiler', 'runtime'); 101 _runtimeOutputDir = path.join(outputDir, 'dev_compiler', 'runtime');
97 } 102 }
98 _dartCore = context.typeProvider.objectType.element.library; 103 _dartCore = context.typeProvider.objectType.element.library;
99 } 104 }
100 105
101 ErrorCollector get reporter => checker.reporter; 106 ErrorCollector get reporter => checker.reporter;
102 107
103 void reset() {
104 _compiled.clear();
105 _sdkCopied = false;
106 }
107
108 /// Compiles every file in [options.inputs]. 108 /// Compiles every file in [options.inputs].
109 /// Returns true on successful compile. 109 /// Returns true on successful compile.
110 bool run() { 110 bool run() {
111 var clock = new Stopwatch()..start(); 111 var clock = new Stopwatch()..start();
112 options.inputs.forEach(compileFromUriString); 112 options.inputs.forEach(compileFromUriString);
113 clock.stop(); 113 clock.stop();
114 var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2); 114 var time = (clock.elapsedMilliseconds / 1000).toStringAsFixed(2);
115 _log.fine('Compiled ${_compiled.length} libraries in ${time} s\n'); 115 _log.fine('Compiled ${_compilationRecord.length} libraries in ${time} s\n');
116 116
117 return !_failure; 117 return !_failure;
118 } 118 }
119 119
120 void compileFromUriString(String uriString) { 120 void compileFromUriString(String uriString, [CompilationNotifier notifier]) {
121 _compileFromUri(stringToUri(uriString)); 121 _compileFromUri(stringToUri(uriString), notifier);
122 } 122 }
123 123
124 void _compileFromUri(Uri uri) { 124 void _compileFromUri(Uri uri, CompilationNotifier notifier) {
125 _failure = false;
125 if (!uri.isAbsolute) { 126 if (!uri.isAbsolute) {
126 throw new ArgumentError.value('$uri', 'uri', 'must be absolute'); 127 throw new ArgumentError.value('$uri', 'uri', 'must be absolute');
127 } 128 }
128 var source = context.sourceFactory.forUri(Uri.encodeFull('$uri')); 129 var source = context.sourceFactory.forUri(Uri.encodeFull('$uri'));
129 if (source == null) { 130 if (source == null) {
130 throw new ArgumentError.value('$uri', 'uri', 'could not find source for'); 131 throw new ArgumentError.value('$uri', 'uri', 'could not find source for');
131 } 132 }
132 compileSource(source); 133 _compileSource(source, notifier);
133 } 134 }
134 135
135 void compileSource(Source source) { 136 void _compileSource(Source source, CompilationNotifier notifier) {
136 if (AnalysisEngine.isHtmlFileName(source.uri.path)) { 137 if (AnalysisEngine.isHtmlFileName(source.uri.path)) {
137 _compileHtml(source); 138 _compileHtml(source, notifier);
138 } else { 139 } else {
139 _compileLibrary(context.computeLibraryElement(source)); 140 _compileLibrary(context.computeLibraryElement(source), notifier);
140 } 141 }
142 _processPending();
141 reporter.flush(); 143 reporter.flush();
142 } 144 }
143 145
144 void _compileLibrary(LibraryElement library) { 146 void _processPending() {
145 if (!_compiled.add(library)) return; 147 // _pendingLibraries was recorded in post-order. Process from the end
148 // to ensure reverse post-order. This will ensure that we handle back
149 // edges from the original depth-first search correctly.
150
151 while (_pendingLibraries.isNotEmpty) {
152 var unit = _pendingLibraries.removeLast();
153 var library = unit.library.element.enclosingElement;
154 assert(_compilationRecord[library] == true);
155
156 // Process dependences one more time to propagate failure from cycles
157 for (var import in library.imports) {
158 if (!_compilationRecord[import.importedLibrary]) {
159 _compilationRecord[library] = false;
160 }
161 }
162 for (var export in library.exports) {
163 if (!_compilationRecord[export.exportedLibrary]) {
164 _compilationRecord[library] = false;
165 }
166 }
167
168 // Generate code if still valid
169 if (_jsGen != null &&
170 (_compilationRecord[library] ||
171 options.codegenOptions.forceCompile)) {
172 _jsGen.generateLibrary(unit);
173 }
174 }
175 }
176
177 bool _compileLibrary(LibraryElement library, CompilationNotifier notifier) {
178 var success = _compilationRecord[library];
179 if (success != null) {
180 if (!success) _failure = true;
181 return success;
182 }
183
184 // Optimistically mark a library valid until proven otherwise
185 _compilationRecord[library] = true;
146 186
147 if (!options.checkSdk && library.source.uri.scheme == 'dart') { 187 if (!options.checkSdk && library.source.uri.scheme == 'dart') {
188 // We assume the Dart SDK is always valid
148 if (_jsGen != null) _copyDartRuntime(); 189 if (_jsGen != null) _copyDartRuntime();
149 return; 190 return true;
150 } 191 }
151 192
193 // Check dependences to determine if this library type checks
152 // TODO(jmesserly): in incremental mode, we can skip the transitive 194 // TODO(jmesserly): in incremental mode, we can skip the transitive
153 // compile of imports/exports. 195 // compile of imports/exports.
154 _compileLibrary(_dartCore); // implicit dart:core dependency 196 _compileLibrary(_dartCore, notifier); // implicit dart:core dependency
155 for (var import in library.imports) _compileLibrary(import.importedLibrary); 197 for (var import in library.imports) {
156 for (var export in library.exports) _compileLibrary(export.exportedLibrary); 198 if (!_compileLibrary(import.importedLibrary, notifier)) {
199 _compilationRecord[library] = false;
200 }
201 }
202 for (var export in library.exports) {
203 if (!_compileLibrary(export.exportedLibrary, notifier)) {
204 _compilationRecord[library] = false;
205 }
206 }
157 207
208 // Check this library's own code
158 var unitElements = [library.definingCompilationUnit]..addAll(library.parts); 209 var unitElements = [library.definingCompilationUnit]..addAll(library.parts);
159 var units = <CompilationUnit>[]; 210 var units = <CompilationUnit>[];
160 211
161 bool failureInLib = false; 212 bool failureInLib = false;
162 for (var element in unitElements) { 213 for (var element in unitElements) {
163 var unit = context.resolveCompilationUnit(element.source, library); 214 var unit = context.resolveCompilationUnit(element.source, library);
164 units.add(unit); 215 units.add(unit);
165 failureInLib = logErrors(element.source) || failureInLib; 216 failureInLib = logErrors(element.source) || failureInLib;
217 checker.reset();
166 checker.visitCompilationUnit(unit); 218 checker.visitCompilationUnit(unit);
167 if (checker.failure) failureInLib = true; 219 if (checker.failure) failureInLib = true;
168 } 220 }
221 if (failureInLib) _compilationRecord[library] = false;
169 222
170 if (failureInLib) { 223 // Notifier framework if requested
171 _failure = true; 224 if (notifier != null) {
172 if (!options.codegenOptions.forceCompile) return; 225 reporter.flush();
226 notifier(getOutputPath(library.source.uri));
173 } 227 }
174 228
175 if (_jsGen != null) { 229 // Record valid libraries for further dependence checking (cycles) and
230 // codegen.
231
232 // TODO(vsm): Restructure this to not delay code generation more than
233 // necessary. We'd like to process the AST before there is any chance
234 // it's cached out. We should refactor common logic in
235 // server/dependency_graph and perhaps the analyzer itself.
236 success = _compilationRecord[library];
237 if (success || options.codegenOptions.forceCompile) {
176 var unit = units.first; 238 var unit = units.first;
177 var parts = units.skip(1).toList(); 239 var parts = units.skip(1).toList();
178 _jsGen.generateLibrary(new LibraryUnit(unit, parts)); 240 _pendingLibraries.add(new LibraryUnit(unit, parts));
179 } 241 }
242
243 // Return tentative success status.
244 if (!success) _failure = true;
245 return success;
180 } 246 }
181 247
182 void _copyDartRuntime() { 248 void _copyDartRuntime() {
183 if (_sdkCopied) return; 249 if (_sdkCopied) return;
184 _sdkCopied = true; 250 _sdkCopied = true;
185 for (var file in defaultRuntimeFiles) { 251 for (var file in defaultRuntimeFiles) {
186 var input = new File(path.join(options.runtimeDir, file)); 252 var input = new File(path.join(options.runtimeDir, file));
187 var output = new File(path.join(_runtimeOutputDir, file)); 253 var output = new File(path.join(_runtimeOutputDir, file));
188 if (output.existsSync() && 254 if (output.existsSync() &&
189 output.lastModifiedSync() == input.lastModifiedSync()) { 255 output.lastModifiedSync() == input.lastModifiedSync()) {
190 continue; 256 continue;
191 } 257 }
192 new Directory(path.dirname(output.path)).createSync(recursive: true); 258 new Directory(path.dirname(output.path)).createSync(recursive: true);
193 input.copySync(output.path); 259 input.copySync(output.path);
194 } 260 }
195 } 261 }
196 262
197 void _compileHtml(Source source) { 263 void _compileHtml(Source source, CompilationNotifier notifier) {
198 // TODO(jmesserly): reuse DartScriptsTask instead of copy/paste. 264 // TODO(jmesserly): reuse DartScriptsTask instead of copy/paste.
199 var contents = context.getContents(source); 265 var contents = context.getContents(source);
200 var document = html.parse(contents.data, generateSpans: true); 266 var document = html.parse(contents.data, generateSpans: true);
201 var scripts = document.querySelectorAll('script[type="application/dart"]'); 267 var scripts = document.querySelectorAll('script[type="application/dart"]');
202 268
203 var loadedLibs = new LinkedHashSet<Uri>(); 269 var loadedLibs = new LinkedHashSet<Uri>();
204 270
205 var htmlOutDir = path.dirname(getOutputPath(source.uri)); 271 var htmlOutDir = path.dirname(getOutputPath(source.uri));
206 for (var script in scripts) { 272 for (var script in scripts) {
207 Source scriptSource = null; 273 Source scriptSource = null;
208 var srcAttr = script.attributes['src']; 274 var srcAttr = script.attributes['src'];
209 if (srcAttr == null) { 275 if (srcAttr == null) {
210 if (script.hasContent()) { 276 if (script.hasContent()) {
211 var fragments = <ScriptFragment>[]; 277 var fragments = <ScriptFragment>[];
212 for (var node in script.nodes) { 278 for (var node in script.nodes) {
213 if (node is html.Text) { 279 if (node is html.Text) {
214 var start = node.sourceSpan.start; 280 var start = node.sourceSpan.start;
215 fragments.add(new ScriptFragment( 281 fragments.add(new ScriptFragment(
216 start.offset, start.line, start.column, node.data)); 282 start.offset, start.line, start.column, node.data));
217 } 283 }
218 } 284 }
219 scriptSource = new DartScript(source, fragments); 285 scriptSource = new DartScript(source, fragments);
220 } 286 }
221 } else if (AnalysisEngine.isDartFileName(srcAttr)) { 287 } else if (AnalysisEngine.isDartFileName(srcAttr)) {
222 scriptSource = context.sourceFactory.resolveUri(source, srcAttr); 288 scriptSource = context.sourceFactory.resolveUri(source, srcAttr);
223 } 289 }
224 290
225 if (scriptSource != null) { 291 if (scriptSource != null) {
226 var lib = context.computeLibraryElement(scriptSource); 292 var lib = context.computeLibraryElement(scriptSource);
227 _compileLibrary(lib); 293 _compileLibrary(lib, notifier);
228 script.replaceWith(_linkLibraries(lib, loadedLibs, from: htmlOutDir)); 294 script.replaceWith(_linkLibraries(lib, loadedLibs, from: htmlOutDir));
229 } 295 }
230 } 296 }
231 297
232 new File(getOutputPath(source.uri)).openSync(mode: FileMode.WRITE) 298 new File(getOutputPath(source.uri)).openSync(mode: FileMode.WRITE)
233 ..writeStringSync(document.outerHtml) 299 ..writeStringSync(document.outerHtml)
234 ..writeStringSync('\n') 300 ..writeStringSync('\n')
235 ..closeSync(); 301 ..closeSync();
236 } 302 }
237 303
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 '_rtti.js', 519 '_rtti.js',
454 '_classes.js', 520 '_classes.js',
455 '_operations.js', 521 '_operations.js',
456 'dart_runtime.js', 522 'dart_runtime.js',
457 ]; 523 ];
458 files.addAll(corelibOrder.map((l) => l.replaceAll('.', '/') + '.js')); 524 files.addAll(corelibOrder.map((l) => l.replaceAll('.', '/') + '.js'));
459 return files; 525 return files;
460 }(); 526 }();
461 527
462 final _log = new Logger('dev_compiler.src.compiler'); 528 final _log = new Logger('dev_compiler.src.compiler');
OLDNEW
« no previous file with comments | « lib/src/checker/checker.dart ('k') | test/codegen/expect/DeltaBlue.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698