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

Side by Side Diff: pkg/front_end/lib/src/incremental/kernel_driver.dart

Issue 2976003002: Implement IncrementalKernelGeneratorImpl using KernelDriver. (Closed)
Patch Set: Created 3 years, 5 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 | « no previous file | pkg/front_end/lib/src/incremental_kernel_generator_impl.dart » ('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) 2017, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2017, 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 import 'dart:async'; 5 import 'dart:async';
6 6
7 import 'package:front_end/file_system.dart'; 7 import 'package:front_end/file_system.dart';
8 import 'package:front_end/incremental_kernel_generator.dart';
9 import 'package:front_end/src/base/api_signature.dart'; 8 import 'package:front_end/src/base/api_signature.dart';
10 import 'package:front_end/src/base/performace_logger.dart'; 9 import 'package:front_end/src/base/performace_logger.dart';
11 import 'package:front_end/src/base/processed_options.dart';
12 import 'package:front_end/src/fasta/dill/dill_library_builder.dart'; 10 import 'package:front_end/src/fasta/dill/dill_library_builder.dart';
13 import 'package:front_end/src/fasta/dill/dill_target.dart'; 11 import 'package:front_end/src/fasta/dill/dill_target.dart';
14 import 'package:front_end/src/fasta/kernel/kernel_target.dart'; 12 import 'package:front_end/src/fasta/kernel/kernel_target.dart';
15 import 'package:front_end/src/fasta/kernel/utils.dart'; 13 import 'package:front_end/src/fasta/kernel/utils.dart';
16 import 'package:front_end/src/fasta/ticker.dart'; 14 import 'package:front_end/src/fasta/ticker.dart';
17 import 'package:front_end/src/fasta/translate_uri.dart'; 15 import 'package:front_end/src/fasta/translate_uri.dart';
18 import 'package:front_end/src/incremental/byte_store.dart'; 16 import 'package:front_end/src/incremental/byte_store.dart';
19 import 'package:front_end/src/incremental/file_state.dart'; 17 import 'package:front_end/src/incremental/file_state.dart';
20 import 'package:kernel/binary/ast_from_binary.dart'; 18 import 'package:kernel/binary/ast_from_binary.dart';
21 import 'package:kernel/kernel.dart' hide Source; 19 import 'package:kernel/kernel.dart' hide Source;
22 import 'package:kernel/target/targets.dart' show TargetFlags; 20 import 'package:kernel/target/targets.dart' show TargetFlags;
23 import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget; 21 import 'package:kernel/target/vm_fasta.dart' show VmFastaTarget;
24 import 'package:meta/meta.dart'; 22 import 'package:meta/meta.dart';
25 23
26 /// Implementation of [IncrementalKernelGenerator]. 24 /// TODO(scheglov) document
25 typedef Future<Null> KernelDriverFileAddedFn(Uri uri);
26
27 /// This class computes [LibraryCycleResult]s for Dart files.
27 /// 28 ///
28 /// TODO(scheglov) Update the documentation. 29 /// TODO(scheglov) Improve the documentation.
Paul Berry 2017/07/12 17:04:43 Would you mind adding documentation before landing
29 /// 30 class KernelDriver {
30 /// Theory of operation: an instance of [IncrementalResolvedAstGenerator] is
31 /// used to obtain resolved ASTs, and these are fed into kernel code generation
32 /// logic.
33 class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator {
34 /// The version of data format, should be incremented on every format change. 31 /// The version of data format, should be incremented on every format change.
35 static const int DATA_VERSION = 1; 32 static const int DATA_VERSION = 1;
36 33
37 /// The compiler options, such as the [FileSystem], the SDK dill location, 34 /// The logger to report compilation progress.
38 /// etc. 35 final PerformanceLog _logger;
39 final ProcessedOptions _options; 36
37 /// The [FileSystem] which should be used by the front end to access files.
38 final FileSystem _fileSystem;
39
40 /// The byte storage to get and put serialized data.
41 final ByteStore _byteStore;
40 42
41 /// The object that knows how to resolve "package:" and "dart:" URIs. 43 /// The object that knows how to resolve "package:" and "dart:" URIs.
42 final TranslateUri _uriTranslator; 44 final TranslateUri _uriTranslator;
43 45
44 /// The logger to report compilation progress. 46 /// Is `true` if strong mode analysis should be used.
45 final PerformanceLog _logger; 47 final bool _strongMode;
46 48
47 /// The byte storage to get and put serialized data. 49 /// TODO(scheglov) document
48 final ByteStore _byteStore; 50 final KernelDriverFileAddedFn _fileAddedFn;
49
50 /// The URI of the program entry point.
51 final Uri _entryPoint;
52
53 /// The function to notify when files become used or unused, or `null`.
54 final WatchUsedFilesFn _watchFn;
55 51
56 /// The salt to mix into all hashes used as keys for serialized data. 52 /// The salt to mix into all hashes used as keys for serialized data.
57 List<int> _salt; 53 List<int> _salt;
58 54
59 /// The current file system state. 55 /// The current file system state.
60 FileSystemState _fsState; 56 FileSystemState _fsState;
61 57
62 /// Latest compilation signatures produced by [computeDelta] for libraries.
63 final Map<Uri, String> _latestSignature = {};
64
65 /// The set of absolute file URIs that were reported through [invalidate] 58 /// The set of absolute file URIs that were reported through [invalidate]
66 /// and not checked for actual changes yet. 59 /// and not checked for actual changes yet.
67 final Set<Uri> _invalidatedFiles = new Set<Uri>(); 60 final Set<Uri> _invalidatedFiles = new Set<Uri>();
68 61
69 /// The object that provides additional information for tests. 62 /// The object that provides additional information for tests.
70 final _TestView _testView = new _TestView(); 63 final _TestView _testView = new _TestView();
71 64
72 IncrementalKernelGeneratorImpl( 65 KernelDriver(this._logger, this._fileSystem, this._byteStore,
73 this._options, this._uriTranslator, this._entryPoint, 66 this._uriTranslator, this._strongMode,
74 {WatchUsedFilesFn watch}) 67 {KernelDriverFileAddedFn fileAddedFn})
75 : _logger = _options.logger, 68 : _fileAddedFn = fileAddedFn {
76 _byteStore = _options.byteStore,
77 _watchFn = watch {
78 _computeSalt(); 69 _computeSalt();
79 70
80 Future<Null> onFileAdded(Uri uri) { 71 Future<Null> onFileAdded(Uri uri) {
81 if (_watchFn != null) { 72 if (_fileAddedFn != null) {
82 return _watchFn(uri, true); 73 return _fileAddedFn(uri);
83 } 74 }
84 return new Future.value(); 75 return new Future.value();
85 } 76 }
86 77
87 _fsState = new FileSystemState(_options.byteStore, _options.fileSystem, 78 _fsState = new FileSystemState(
88 _uriTranslator, _salt, onFileAdded); 79 _byteStore, _fileSystem, _uriTranslator, _salt, onFileAdded);
89 } 80 }
90 81
82 /// TODO(scheglov) document
83 FileSystemState get fsState => _fsState;
84
91 /// Return the object that provides additional information for tests. 85 /// Return the object that provides additional information for tests.
92 @visibleForTesting 86 @visibleForTesting
93 _TestView get test => _testView; 87 _TestView get test => _testView;
94 88
95 @override 89 /// TODO(scheglov) document
96 Future<DeltaProgram> computeDelta() async { 90 Future<KernelResult> getKernel(Uri uri) async {
97 return await _logger.runAsync('Compute delta', () async { 91 return await _logger.runAsync('Compute delta', () async {
98 await _refreshInvalidatedFiles(); 92 await _refreshInvalidatedFiles();
99 93
100 // Ensure that the graph starting at the entry point is ready. 94 // Ensure that the graph starting at the entry point is ready.
101 FileState entryLibrary = 95 FileState entryLibrary =
102 await _logger.runAsync('Build graph of files', () async { 96 await _logger.runAsync('Build graph of files', () async {
103 return await _fsState.getFile(_entryPoint); 97 return await _fsState.getFile(uri);
104 }); 98 });
105 99
106 List<LibraryCycle> cycles = _logger.run('Compute library cycles', () { 100 List<LibraryCycle> cycles = _logger.run('Compute library cycles', () {
107 List<LibraryCycle> cycles = entryLibrary.topologicalOrder; 101 List<LibraryCycle> cycles = entryLibrary.topologicalOrder;
108 _logger.writeln('Computed ${cycles.length} cycles.'); 102 _logger.writeln('Computed ${cycles.length} cycles.');
109 return cycles; 103 return cycles;
110 }); 104 });
111 105
112 CanonicalName nameRoot = new CanonicalName.root(); 106 CanonicalName nameRoot = new CanonicalName.root();
113 DillTarget dillTarget = new DillTarget( 107 DillTarget dillTarget = new DillTarget(
114 new Ticker(isVerbose: false), 108 new Ticker(isVerbose: false),
115 _uriTranslator, 109 _uriTranslator,
116 new VmFastaTarget(new TargetFlags(strongMode: _options.strongMode))); 110 new VmFastaTarget(new TargetFlags(strongMode: _strongMode)));
117 111
118 List<_LibraryCycleResult> results = []; 112 List<LibraryCycleResult> results = [];
119 _testView.compiledCycles.clear(); 113 _testView.compiledCycles.clear();
120 await _logger.runAsync('Compute results for cycles', () async { 114 await _logger.runAsync('Compute results for cycles', () async {
121 for (LibraryCycle cycle in cycles) { 115 for (LibraryCycle cycle in cycles) {
122 _LibraryCycleResult result = 116 LibraryCycleResult result =
123 await _compileCycle(nameRoot, dillTarget, cycle); 117 await _compileCycle(nameRoot, dillTarget, cycle);
124 results.add(result); 118 results.add(result);
125 } 119 }
126 }); 120 });
127 121
128 Program program = new Program(nameRoot: nameRoot); 122 return new KernelResult(nameRoot, results);
129
130 // The set of affected library cycles (have different signatures).
131 final affectedLibraryCycles = new Set<LibraryCycle>();
132 for (_LibraryCycleResult result in results) {
133 for (Library library in result.kernelLibraries) {
134 Uri uri = library.importUri;
135 if (_latestSignature[uri] != result.signature) {
136 _latestSignature[uri] = result.signature;
137 affectedLibraryCycles.add(result.cycle);
138 }
139 }
140 }
141
142 // The set of affected library cycles (have different signatures),
143 // or libraries that import or export affected libraries (so VM might
144 // have inlined some code from affected libraries into them).
145 final vmRequiredLibraryCycles = new Set<LibraryCycle>();
146
147 void gatherVmRequiredLibraryCycles(LibraryCycle cycle) {
148 if (vmRequiredLibraryCycles.add(cycle)) {
149 cycle.directUsers.forEach(gatherVmRequiredLibraryCycles);
150 }
151 }
152
153 affectedLibraryCycles.forEach(gatherVmRequiredLibraryCycles);
154
155 // Add required libraries.
156 for (_LibraryCycleResult result in results) {
157 if (vmRequiredLibraryCycles.contains(result.cycle)) {
158 for (Library library in result.kernelLibraries) {
159 program.libraries.add(library);
160 library.parent = program;
161 }
162 }
163 }
164
165 // Set the main method.
166 if (program.libraries.isNotEmpty) {
167 for (Library library in results.last.kernelLibraries) {
168 if (library.importUri == _entryPoint) {
169 program.mainMethod = library.procedures.firstWhere(
170 (procedure) => procedure.name.name == 'main',
171 orElse: () => null);
172 break;
173 }
174 }
175 }
176
177 return new DeltaProgram(program);
178 }); 123 });
179 } 124 }
180 125
181 @override 126 /// TODO(scheglov) document
182 void invalidate(Uri uri) { 127 void invalidate(Uri uri) {
183 _invalidatedFiles.add(uri); 128 _invalidatedFiles.add(uri);
184 } 129 }
185 130
186 @override 131 /// TODO(scheglov) document
187 void invalidateAll() { 132 void invalidateAll() {
188 _invalidatedFiles.addAll(_fsState.fileUris); 133 _invalidatedFiles.addAll(_fsState.fileUris);
189 } 134 }
190 135
191 /// Ensure that [dillTarget] includes the [cycle] libraries. It already 136 /// Ensure that [dillTarget] includes the [cycle] libraries. It already
192 /// contains all the libraries that sorted before the given [cycle] in 137 /// contains all the libraries that sorted before the given [cycle] in
193 /// topological order. Return the result with the cycle libraries. 138 /// topological order. Return the result with the cycle libraries.
194 Future<_LibraryCycleResult> _compileCycle( 139 Future<LibraryCycleResult> _compileCycle(
195 CanonicalName nameRoot, DillTarget dillTarget, LibraryCycle cycle) async { 140 CanonicalName nameRoot, DillTarget dillTarget, LibraryCycle cycle) async {
196 return _logger.runAsync('Compile cycle $cycle', () async { 141 return _logger.runAsync('Compile cycle $cycle', () async {
197 String signature = _getCycleSignature(cycle); 142 String signature = _getCycleSignature(cycle);
198 143
199 _logger.writeln('Signature: $signature.'); 144 _logger.writeln('Signature: $signature.');
200 var kernelKey = '$signature.kernel'; 145 var kernelKey = '$signature.kernel';
201 146
202 // We need kernel libraries for these URIs. 147 // We need kernel libraries for these URIs.
203 var libraryUris = new Set<Uri>(); 148 var libraryUris = new Set<Uri>();
204 var libraryUriToFile = <Uri, FileState>{}; 149 var libraryUriToFile = <Uri, FileState>{};
(...skipping 17 matching lines...) Expand all
222 // Check if there is already a bundle with these libraries. 167 // Check if there is already a bundle with these libraries.
223 List<int> bytes = _byteStore.get(kernelKey); 168 List<int> bytes = _byteStore.get(kernelKey);
224 if (bytes != null) { 169 if (bytes != null) {
225 return _logger.runAsync('Read serialized libraries', () async { 170 return _logger.runAsync('Read serialized libraries', () async {
226 var program = new Program(nameRoot: nameRoot); 171 var program = new Program(nameRoot: nameRoot);
227 var reader = new BinaryBuilder(bytes); 172 var reader = new BinaryBuilder(bytes);
228 reader.readProgram(program); 173 reader.readProgram(program);
229 174
230 await appendNewDillLibraries(program); 175 await appendNewDillLibraries(program);
231 176
232 return new _LibraryCycleResult(cycle, signature, program.libraries); 177 return new LibraryCycleResult(cycle, signature, program.libraries);
233 }); 178 });
234 } 179 }
235 180
236 // Create KernelTarget and configure it for compiling the cycle URIs. 181 // Create KernelTarget and configure it for compiling the cycle URIs.
237 KernelTarget kernelTarget = 182 KernelTarget kernelTarget =
238 new KernelTarget(_fsState.fileSystemView, dillTarget, _uriTranslator); 183 new KernelTarget(_fsState.fileSystemView, dillTarget, _uriTranslator);
239 for (FileState library in cycle.libraries) { 184 for (FileState library in cycle.libraries) {
240 kernelTarget.read(library.uri); 185 kernelTarget.read(library.uri);
241 } 186 }
242 187
(...skipping 13 matching lines...) Expand all
256 .toList(); 201 .toList();
257 202
258 _logger.run('Serialize ${kernelLibraries.length} libraries', () { 203 _logger.run('Serialize ${kernelLibraries.length} libraries', () {
259 program.uriToSource.clear(); 204 program.uriToSource.clear();
260 List<int> bytes = 205 List<int> bytes =
261 serializeProgram(program, filter: kernelLibraries.contains); 206 serializeProgram(program, filter: kernelLibraries.contains);
262 _byteStore.put(kernelKey, bytes); 207 _byteStore.put(kernelKey, bytes);
263 _logger.writeln('Stored ${bytes.length} bytes.'); 208 _logger.writeln('Stored ${bytes.length} bytes.');
264 }); 209 });
265 210
266 return new _LibraryCycleResult(cycle, signature, kernelLibraries); 211 return new LibraryCycleResult(cycle, signature, kernelLibraries);
267 }); 212 });
268 } 213 }
269 214
270 /// Compute exports scopes for a new strongly connected cycle of [libraries]. 215 /// Compute exports scopes for a new strongly connected cycle of [libraries].
271 /// The [dillTarget] can be used to access libraries from previous cycles. 216 /// The [dillTarget] can be used to access libraries from previous cycles.
272 /// TODO(scheglov) Remove/replace this when Kernel has export scopes. 217 /// TODO(scheglov) Remove/replace this when Kernel has export scopes.
273 void _computeExportScopes(DillTarget dillTarget, 218 void _computeExportScopes(DillTarget dillTarget,
274 Map<Uri, FileState> uriToFile, List<DillLibraryBuilder> libraries) { 219 Map<Uri, FileState> uriToFile, List<DillLibraryBuilder> libraries) {
275 bool wasChanged = false; 220 bool wasChanged = false;
276 do { 221 do {
(...skipping 15 matching lines...) Expand all
292 } 237 }
293 } 238 }
294 } 239 }
295 } while (wasChanged); 240 } while (wasChanged);
296 } 241 }
297 242
298 /// Compute salt and put into [_salt]. 243 /// Compute salt and put into [_salt].
299 void _computeSalt() { 244 void _computeSalt() {
300 var saltBuilder = new ApiSignature(); 245 var saltBuilder = new ApiSignature();
301 saltBuilder.addInt(DATA_VERSION); 246 saltBuilder.addInt(DATA_VERSION);
302 saltBuilder.addBool(_options.strongMode); 247 saltBuilder.addBool(_strongMode);
303 saltBuilder.addString(_entryPoint.toString());
304 _salt = saltBuilder.toByteList(); 248 _salt = saltBuilder.toByteList();
305 } 249 }
306 250
307 String _getCycleSignature(LibraryCycle cycle) { 251 String _getCycleSignature(LibraryCycle cycle) {
308 bool hasMixinApplication = 252 bool hasMixinApplication =
309 cycle.libraries.any((library) => library.hasMixinApplicationLibrary); 253 cycle.libraries.any((library) => library.hasMixinApplicationLibrary);
310 var signatureBuilder = new ApiSignature(); 254 var signatureBuilder = new ApiSignature();
311 signatureBuilder.addBytes(_salt); 255 signatureBuilder.addBytes(_salt);
312 Set<FileState> transitiveFiles = cycle.libraries 256 Set<FileState> transitiveFiles = cycle.libraries
313 .map((library) => library.transitiveFiles) 257 .map((library) => library.transitiveFiles)
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 _invalidatedFiles.clear(); 291 _invalidatedFiles.clear();
348 292
349 // Refresh the files. 293 // Refresh the files.
350 for (var fileUri in invalidatedFiles) { 294 for (var fileUri in invalidatedFiles) {
351 var file = _fsState.getFileByFileUri(fileUri); 295 var file = _fsState.getFileByFileUri(fileUri);
352 if (file != null) { 296 if (file != null) {
353 _logger.writeln('Refresh $fileUri'); 297 _logger.writeln('Refresh $fileUri');
354 await file.refresh(); 298 await file.refresh();
355 } 299 }
356 } 300 }
357
358 // The file graph might have changed, perform GC.
359 var removedFiles = _fsState.gc(_entryPoint);
360 if (removedFiles.isNotEmpty && _watchFn != null) {
361 for (var removedFile in removedFiles) {
362 await _watchFn(removedFile.fileUri, false);
363 }
364 }
365 }); 301 });
366 } 302 }
367 } 303 }
368 304
305 /// TODO(scheglov) document
306 class KernelResult {
307 final CanonicalName nameRoot;
308 final List<LibraryCycleResult> results;
309
310 KernelResult(this.nameRoot, this.results);
311 }
312
369 /// Compilation result for a library cycle. 313 /// Compilation result for a library cycle.
370 class _LibraryCycleResult { 314 class LibraryCycleResult {
371 final LibraryCycle cycle; 315 final LibraryCycle cycle;
372 316
373 /// The signature of the result. 317 /// The signature of the result.
374 /// 318 ///
375 /// It is based on the full content of the libraries in the [cycle], and 319 /// It is based on the full content of the libraries in the [cycle], and
376 /// either API signatures of the transitive dependencies (usually), or 320 /// either API signatures of the transitive dependencies (usually), or
377 /// the full content of them (in the [cycle] has a library with a mixin 321 /// the full content of them (in the [cycle] has a library with a mixin
378 /// application). 322 /// application).
379 final String signature; 323 final String signature;
380 324
381 /// Kernel libraries for libraries in the [cycle]. Bodies of dependencies 325 /// Kernel libraries for libraries in the [cycle]. Bodies of dependencies
382 /// are not included, but but references to those dependencies are included. 326 /// are not included, but but references to those dependencies are included.
383 final List<Library> kernelLibraries; 327 final List<Library> kernelLibraries;
384 328
385 _LibraryCycleResult(this.cycle, this.signature, this.kernelLibraries); 329 LibraryCycleResult(this.cycle, this.signature, this.kernelLibraries);
386 } 330 }
387 331
388 @visibleForTesting 332 @visibleForTesting
389 class _TestView { 333 class _TestView {
390 /// The list of [LibraryCycle]s compiled for the last delta. 334 /// The list of [LibraryCycle]s compiled for the last delta.
391 /// It does not include libraries which were read from the cache. 335 /// It does not include libraries which were read from the cache.
392 final List<LibraryCycle> compiledCycles = []; 336 final List<LibraryCycle> compiledCycles = [];
393 } 337 }
OLDNEW
« no previous file with comments | « no previous file | pkg/front_end/lib/src/incremental_kernel_generator_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698