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

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: Flush on demand 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>{};
Jennifer Messerly 2015/10/02 18:22:35 minor: do we care about order? if not, a HashMap i
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.containsKey(library) &&
155 _compilationRecord[library]);
156
157 // Process dependences one more time to propagate failure from cycles
158 for (var import in library.imports) {
159 if (!_compilationRecord[import.importedLibrary]) {
160 _compilationRecord[library] = false;
161 }
162 }
163 for (var export in library.exports) {
164 if (!_compilationRecord[export.exportedLibrary]) {
165 _compilationRecord[library] = false;
166 }
167 }
168
169 // Generate code if still valid
170 if (_jsGen != null &&
171 (_compilationRecord[library] ||
172 options.codegenOptions.forceCompile)) {
173 _jsGen.generateLibrary(unit);
174 }
175 }
176 }
177
178 bool _compileLibrary(LibraryElement library, CompilationNotifier notifier) {
179 if (_compilationRecord.containsKey(library)) {
180 if (!_compilationRecord[library]) _failure = true;
181 return _compilationRecord[library];
182 }
146 183
147 if (!options.checkSdk && library.source.uri.scheme == 'dart') { 184 if (!options.checkSdk && library.source.uri.scheme == 'dart') {
185 // We assume the Dart SDK is always valid
148 if (_jsGen != null) _copyDartRuntime(); 186 if (_jsGen != null) _copyDartRuntime();
149 return; 187 _compilationRecord[library] = true;
188 return true;
150 } 189 }
151 190
152 // TODO(jmesserly): in incremental mode, we can skip the transitive 191 // Check this library's own code
153 // compile of imports/exports.
154 _compileLibrary(_dartCore); // implicit dart:core dependency
155 for (var import in library.imports) _compileLibrary(import.importedLibrary);
156 for (var export in library.exports) _compileLibrary(export.exportedLibrary);
157
158 var unitElements = [library.definingCompilationUnit]..addAll(library.parts); 192 var unitElements = [library.definingCompilationUnit]..addAll(library.parts);
159 var units = <CompilationUnit>[]; 193 var units = <CompilationUnit>[];
160 194
161 bool failureInLib = false; 195 bool failureInLib = false;
162 for (var element in unitElements) { 196 for (var element in unitElements) {
163 var unit = context.resolveCompilationUnit(element.source, library); 197 var unit = context.resolveCompilationUnit(element.source, library);
164 units.add(unit); 198 units.add(unit);
165 failureInLib = logErrors(element.source) || failureInLib; 199 failureInLib = logErrors(element.source) || failureInLib;
200 checker.reset();
166 checker.visitCompilationUnit(unit); 201 checker.visitCompilationUnit(unit);
167 if (checker.failure) failureInLib = true; 202 if (checker.failure) failureInLib = true;
168 } 203 }
204 _compilationRecord[library] = !failureInLib;
169 205
170 if (failureInLib) { 206 // Notifier framework if requested
171 _failure = true; 207 if (notifier != null) {
172 if (!options.codegenOptions.forceCompile) return; 208 reporter.flush();
209 notifier(getOutputPath(library.source.uri));
173 } 210 }
174 211
175 if (_jsGen != null) { 212 // Check dependences to determine if this library type checks
213
214 // TODO(jmesserly): in incremental mode, we can skip the transitive
215 // compile of imports/exports.
216 _compileLibrary(_dartCore, notifier); // implicit dart:core dependency
217 for (var import in library.imports) {
218 if (!_compileLibrary(import.importedLibrary, notifier)) {
219 _compilationRecord[library] = false;
220 }
221 }
222 for (var export in library.exports) {
223 if (!_compileLibrary(export.exportedLibrary, notifier)) {
224 _compilationRecord[library] = false;
225 }
226 }
227
228 // Record valid libraries for further dependence checking (cycles) and
229 // codegen.
230 if (_compilationRecord[library] || options.codegenOptions.forceCompile) {
176 var unit = units.first; 231 var unit = units.first;
177 var parts = units.skip(1).toList(); 232 var parts = units.skip(1).toList();
178 _jsGen.generateLibrary(new LibraryUnit(unit, parts)); 233 _pendingLibraries.add(new LibraryUnit(unit, parts));
179 } 234 }
235
236 // Return tentative success status.
237 if (!_compilationRecord[library]) _failure = true;
238 return _compilationRecord[library];
180 } 239 }
181 240
182 void _copyDartRuntime() { 241 void _copyDartRuntime() {
183 if (_sdkCopied) return; 242 if (_sdkCopied) return;
184 _sdkCopied = true; 243 _sdkCopied = true;
185 for (var file in defaultRuntimeFiles) { 244 for (var file in defaultRuntimeFiles) {
186 var input = new File(path.join(options.runtimeDir, file)); 245 var input = new File(path.join(options.runtimeDir, file));
187 var output = new File(path.join(_runtimeOutputDir, file)); 246 var output = new File(path.join(_runtimeOutputDir, file));
188 if (output.existsSync() && 247 if (output.existsSync() &&
189 output.lastModifiedSync() == input.lastModifiedSync()) { 248 output.lastModifiedSync() == input.lastModifiedSync()) {
190 continue; 249 continue;
191 } 250 }
192 new Directory(path.dirname(output.path)).createSync(recursive: true); 251 new Directory(path.dirname(output.path)).createSync(recursive: true);
193 input.copySync(output.path); 252 input.copySync(output.path);
194 } 253 }
195 } 254 }
196 255
197 void _compileHtml(Source source) { 256 void _compileHtml(Source source, CompilationNotifier notifier) {
198 // TODO(jmesserly): reuse DartScriptsTask instead of copy/paste. 257 // TODO(jmesserly): reuse DartScriptsTask instead of copy/paste.
199 var contents = context.getContents(source); 258 var contents = context.getContents(source);
200 var document = html.parse(contents.data, generateSpans: true); 259 var document = html.parse(contents.data, generateSpans: true);
201 var scripts = document.querySelectorAll('script[type="application/dart"]'); 260 var scripts = document.querySelectorAll('script[type="application/dart"]');
202 261
203 var loadedLibs = new LinkedHashSet<Uri>(); 262 var loadedLibs = new LinkedHashSet<Uri>();
204 263
205 var htmlOutDir = path.dirname(getOutputPath(source.uri)); 264 var htmlOutDir = path.dirname(getOutputPath(source.uri));
206 for (var script in scripts) { 265 for (var script in scripts) {
207 Source scriptSource = null; 266 Source scriptSource = null;
208 var srcAttr = script.attributes['src']; 267 var srcAttr = script.attributes['src'];
209 if (srcAttr == null) { 268 if (srcAttr == null) {
210 if (script.hasContent()) { 269 if (script.hasContent()) {
211 var fragments = <ScriptFragment>[]; 270 var fragments = <ScriptFragment>[];
212 for (var node in script.nodes) { 271 for (var node in script.nodes) {
213 if (node is html.Text) { 272 if (node is html.Text) {
214 var start = node.sourceSpan.start; 273 var start = node.sourceSpan.start;
215 fragments.add(new ScriptFragment( 274 fragments.add(new ScriptFragment(
216 start.offset, start.line, start.column, node.data)); 275 start.offset, start.line, start.column, node.data));
217 } 276 }
218 } 277 }
219 scriptSource = new DartScript(source, fragments); 278 scriptSource = new DartScript(source, fragments);
220 } 279 }
221 } else if (AnalysisEngine.isDartFileName(srcAttr)) { 280 } else if (AnalysisEngine.isDartFileName(srcAttr)) {
222 scriptSource = context.sourceFactory.resolveUri(source, srcAttr); 281 scriptSource = context.sourceFactory.resolveUri(source, srcAttr);
223 } 282 }
224 283
225 if (scriptSource != null) { 284 if (scriptSource != null) {
226 var lib = context.computeLibraryElement(scriptSource); 285 var lib = context.computeLibraryElement(scriptSource);
227 _compileLibrary(lib); 286 _compileLibrary(lib, notifier);
228 script.replaceWith(_linkLibraries(lib, loadedLibs, from: htmlOutDir)); 287 script.replaceWith(_linkLibraries(lib, loadedLibs, from: htmlOutDir));
229 } 288 }
230 } 289 }
231 290
232 new File(getOutputPath(source.uri)).openSync(mode: FileMode.WRITE) 291 new File(getOutputPath(source.uri)).openSync(mode: FileMode.WRITE)
233 ..writeStringSync(document.outerHtml) 292 ..writeStringSync(document.outerHtml)
234 ..writeStringSync('\n') 293 ..writeStringSync('\n')
235 ..closeSync(); 294 ..closeSync();
236 } 295 }
237 296
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 '_rtti.js', 512 '_rtti.js',
454 '_classes.js', 513 '_classes.js',
455 '_operations.js', 514 '_operations.js',
456 'dart_runtime.js', 515 'dart_runtime.js',
457 ]; 516 ];
458 files.addAll(corelibOrder.map((l) => l.replaceAll('.', '/') + '.js')); 517 files.addAll(corelibOrder.map((l) => l.replaceAll('.', '/') + '.js'));
459 return files; 518 return files;
460 }(); 519 }();
461 520
462 final _log = new Logger('dev_compiler.src.compiler'); 521 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