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

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

Issue 2926883003: Compute API signatures of files. (Closed)
Patch Set: Created 3 years, 6 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 import 'dart:typed_data'; 6 import 'dart:typed_data';
7 7
8 import 'package:crypto/crypto.dart'; 8 import 'package:crypto/crypto.dart';
9 import 'package:front_end/file_system.dart'; 9 import 'package:front_end/file_system.dart';
10 import 'package:front_end/src/base/api_signature.dart';
10 import 'package:front_end/src/base/resolve_relative_uri.dart'; 11 import 'package:front_end/src/base/resolve_relative_uri.dart';
11 import 'package:front_end/src/dependency_walker.dart' as graph; 12 import 'package:front_end/src/dependency_walker.dart' as graph;
12 import 'package:front_end/src/fasta/parser/dart_vm_native.dart'; 13 import 'package:front_end/src/fasta/parser/dart_vm_native.dart';
14 import 'package:front_end/src/fasta/parser/listener.dart' show Listener;
15 import 'package:front_end/src/fasta/parser/parser.dart' show Parser, optional;
13 import 'package:front_end/src/fasta/parser/top_level_parser.dart'; 16 import 'package:front_end/src/fasta/parser/top_level_parser.dart';
14 import 'package:front_end/src/fasta/scanner.dart'; 17 import 'package:front_end/src/fasta/scanner.dart';
18 import 'package:front_end/src/fasta/scanner/token_constants.dart'
19 show STRING_TOKEN;
15 import 'package:front_end/src/fasta/source/directive_listener.dart'; 20 import 'package:front_end/src/fasta/source/directive_listener.dart';
16 import 'package:front_end/src/fasta/translate_uri.dart'; 21 import 'package:front_end/src/fasta/translate_uri.dart';
17 import 'package:kernel/target/vm.dart'; 22 import 'package:kernel/target/vm.dart';
18 23
19 /// Information about a file being compiled, explicitly or implicitly. 24 /// Information about a file being compiled, explicitly or implicitly.
20 /// 25 ///
21 /// It provides a consistent view on its properties. 26 /// It provides a consistent view on its properties.
22 /// 27 ///
23 /// The properties are not guaranteed to represent the most recent state 28 /// The properties are not guaranteed to represent the most recent state
24 /// of the file system. To update the file to the most recent state, [refresh] 29 /// of the file system. To update the file to the most recent state, [refresh]
25 /// should be called. 30 /// should be called.
26 class FileState { 31 class FileState {
27 final FileSystemState _fsState; 32 final FileSystemState _fsState;
28 33
29 /// The absolute URI of the file. 34 /// The absolute URI of the file.
30 final Uri uri; 35 final Uri uri;
31 36
32 /// The resolved URI of the file in the file system. 37 /// The resolved URI of the file in the file system.
33 final Uri fileUri; 38 final Uri fileUri;
34 39
35 bool _exists; 40 bool _exists;
36 List<int> _content; 41 List<int> _content;
37 List<int> _contentHash; 42 List<int> _contentHash;
43 List<int> _apiSignature;
38 44
39 List<NamespaceExport> _exports; 45 List<NamespaceExport> _exports;
40 List<FileState> _importedLibraries; 46 List<FileState> _importedLibraries;
41 List<FileState> _exportedLibraries; 47 List<FileState> _exportedLibraries;
42 List<FileState> _partFiles; 48 List<FileState> _partFiles;
43 49
44 Set<FileState> _directReferencedFiles = new Set<FileState>(); 50 Set<FileState> _directReferencedFiles = new Set<FileState>();
45 List<FileState> _directReferencedLibraries = <FileState>[]; 51 List<FileState> _directReferencedLibraries = <FileState>[];
46 52
47 FileState._(this._fsState, this.uri, this.fileUri); 53 FileState._(this._fsState, this.uri, this.fileUri);
48 54
55 /// The MD5 signature of the file API.
56 /// It depends on all non-comment tokens outside the block bodies.
ahe 2017/06/08 12:33:12 How is the MD5 sum represented? As a byte array? C
scheglov 2017/06/09 18:40:59 Done.
57 List<int> get apiSignature => _apiSignature;
58
49 /// The content of the file. 59 /// The content of the file.
50 List<int> get content => _content; 60 List<int> get content => _content;
51 61
52 /// The MD5 hash of the [content]. 62 /// The MD5 hash of the [content].
53 List<int> get contentHash => _contentHash; 63 List<int> get contentHash => _contentHash;
54 64
55 /// Libraries that this library file directly imports or exports. 65 /// Libraries that this library file directly imports or exports.
56 List<FileState> get directReferencedLibraries => _directReferencedLibraries; 66 List<FileState> get directReferencedLibraries => _directReferencedLibraries;
57 67
58 /// Whether the file exists. 68 /// Whether the file exists.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 _content = await entry.readAsBytes(); 120 _content = await entry.readAsBytes();
111 _exists = true; 121 _exists = true;
112 } catch (_) { 122 } catch (_) {
113 _content = new Uint8List(0); 123 _content = new Uint8List(0);
114 _exists = false; 124 _exists = false;
115 } 125 }
116 126
117 // Compute the content hash. 127 // Compute the content hash.
118 _contentHash = md5.convert(_content).bytes; 128 _contentHash = md5.convert(_content).bytes;
119 129
130 // Scan the content.
131 ScannerResult scanResult = _scan();
ahe 2017/06/08 12:33:12 Thinking out loud here, not a review comment: Sin
scheglov 2017/06/09 18:40:59 I don't understand what this means.
132
133 // Compute the API signature.
134 _apiSignature = _computeApiSignature(scanResult.tokens);
135
120 // Parse directives. 136 // Parse directives.
121 ScannerResult scannerResults = _scan();
122 var listener = new _DirectiveListenerWithNative(); 137 var listener = new _DirectiveListenerWithNative();
123 new TopLevelParser(listener).parseUnit(scannerResults.tokens); 138 new TopLevelParser(listener).parseUnit(scanResult.tokens);
124 139
125 // Build the graph. 140 // Build the graph.
126 _importedLibraries = <FileState>[]; 141 _importedLibraries = <FileState>[];
127 _exportedLibraries = <FileState>[]; 142 _exportedLibraries = <FileState>[];
128 _partFiles = <FileState>[]; 143 _partFiles = <FileState>[];
129 _exports = <NamespaceExport>[]; 144 _exports = <NamespaceExport>[];
130 { 145 {
131 FileState coreFile = await _getFileForRelativeUri('dart:core'); 146 FileState coreFile = await _getFileForRelativeUri('dart:core');
132 // TODO(scheglov) add error handling 147 // TODO(scheglov) add error handling
133 if (coreFile != null) { 148 if (coreFile != null) {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 if (uri.toString() != 'dart:core') return; 195 if (uri.toString() != 'dart:core') return;
181 for (String uri in new VmTarget(null).extraRequiredLibraries) { 196 for (String uri in new VmTarget(null).extraRequiredLibraries) {
182 FileState file = await _getFileForRelativeUri(uri); 197 FileState file = await _getFileForRelativeUri(uri);
183 // TODO(scheglov) add error handling 198 // TODO(scheglov) add error handling
184 if (file != null) { 199 if (file != null) {
185 _importedLibraries.add(file); 200 _importedLibraries.add(file);
186 } 201 }
187 } 202 }
188 } 203 }
189 204
205 /// Compute and return the API signature of the file.
206 ///
207 /// The signature is based on non-comment tokens of the file outside
208 /// of function bodies.
209 List<int> _computeApiSignature(Token token) {
210 var parser = new _BodySkippingParser();
211 parser.parseUnit(token);
212
213 ApiSignature apiSignature = new ApiSignature();
214 apiSignature.addBytes(_fsState._salt);
215
216 // Iterate over tokens and skip bodies.
217 Iterator<_BodyRange> bodyIterator = parser.bodyRanges.iterator;
218 bodyIterator.moveNext();
219 for (; token.kind != EOF_TOKEN; token = token.next) {
220 // Move to the body range that ends after the token.
221 while (bodyIterator.current != null &&
222 bodyIterator.current.last < token.charOffset) {
223 bodyIterator.moveNext();
224 }
225 // If the current body range starts before or at the token, skip it.
226 if (bodyIterator.current != null &&
227 bodyIterator.current.first <= token.charOffset) {
228 continue;
229 }
230 // The token is outside of a function body, add it.
231 apiSignature.addString(token.lexeme);
232 }
233
234 return apiSignature.toByteList();
235 }
236
237 /// Exclude all `native 'xyz';` token sequences.
238 void _excludeNativeClauses(Token token) {
239 for (; token.kind != EOF_TOKEN; token = token.next) {
240 if (optional('native', token) &&
241 token.next.kind == STRING_TOKEN &&
242 optional(';', token.next.next)) {
243 token.previous.next = token.next.next;
244 }
245 }
246 }
247
190 /// Return the [FileState] for the given [relativeUri] or `null` if the URI 248 /// Return the [FileState] for the given [relativeUri] or `null` if the URI
191 /// cannot be parsed, cannot correspond any file, etc. 249 /// cannot be parsed, cannot correspond any file, etc.
192 Future<FileState> _getFileForRelativeUri(String relativeUri) async { 250 Future<FileState> _getFileForRelativeUri(String relativeUri) async {
193 if (relativeUri.isEmpty) return null; 251 if (relativeUri.isEmpty) return null;
194 252
195 // Resolve the relative URI into absolute. 253 // Resolve the relative URI into absolute.
196 // The result is either: 254 // The result is either:
197 // 1) The absolute file URI. 255 // 1) The absolute file URI.
198 // 2) The absolute non-file URI, e.g. `package:foo/foo.dart`. 256 // 2) The absolute non-file URI, e.g. `package:foo/foo.dart`.
199 Uri absoluteUri; 257 Uri absoluteUri;
200 try { 258 try {
201 absoluteUri = resolveRelativeUri(uri, Uri.parse(relativeUri)); 259 absoluteUri = resolveRelativeUri(uri, Uri.parse(relativeUri));
202 } on FormatException { 260 } on FormatException {
203 return null; 261 return null;
204 } 262 }
205 263
206 return await _fsState.getFile(absoluteUri); 264 return await _fsState.getFile(absoluteUri);
207 } 265 }
208 266
209 /// Scan the content of the file. 267 /// Scan the content of the file.
210 ScannerResult _scan() { 268 ScannerResult _scan() {
211 var zeroTerminatedBytes = new Uint8List(_content.length + 1); 269 var zeroTerminatedBytes = new Uint8List(_content.length + 1);
212 zeroTerminatedBytes.setRange(0, _content.length, _content); 270 zeroTerminatedBytes.setRange(0, _content.length, _content);
213 return scan(zeroTerminatedBytes); 271 ScannerResult result = scan(zeroTerminatedBytes);
272 _excludeNativeClauses(result.tokens);
273 return result;
214 } 274 }
215 } 275 }
216 276
217 /// Information about known file system state. 277 /// Information about known file system state.
218 class FileSystemState { 278 class FileSystemState {
219 final FileSystem fileSystem; 279 final FileSystem fileSystem;
220 final TranslateUri uriTranslator; 280 final TranslateUri uriTranslator;
281 final List<int> _salt;
221 282
222 _FileSystemView _fileSystemView; 283 _FileSystemView _fileSystemView;
223 284
224 /// Mapping from file URIs to corresponding [FileState]s. 285 /// Mapping from file URIs to corresponding [FileState]s.
225 final Map<Uri, FileState> _uriToFile = {}; 286 final Map<Uri, FileState> _uriToFile = {};
226 287
227 /// Mapping from file URIs to corresponding [FileState]s. 288 /// Mapping from file URIs to corresponding [FileState]s.
228 final Map<Uri, FileState> _fileUriToFile = {}; 289 final Map<Uri, FileState> _fileUriToFile = {};
229 290
230 FileSystemState(this.fileSystem, this.uriTranslator); 291 FileSystemState(this.fileSystem, this.uriTranslator, this._salt);
231 292
232 /// Return the [FileSystem] that is backed by this [FileSystemState]. The 293 /// Return the [FileSystem] that is backed by this [FileSystemState]. The
233 /// files in this [FileSystem] always have the same content as the 294 /// files in this [FileSystem] always have the same content as the
234 /// corresponding [FileState]s, thus avoiding race conditions when a file 295 /// corresponding [FileState]s, thus avoiding race conditions when a file
235 /// is updated on the actual file system. 296 /// is updated on the actual file system.
236 FileSystem get fileSystemView { 297 FileSystem get fileSystemView {
237 return _fileSystemView ??= new _FileSystemView(this); 298 return _fileSystemView ??= new _FileSystemView(this);
238 } 299 }
239 300
240 /// Return the [FileState] for the given [absoluteUri], or `null` if the 301 /// Return the [FileState] for the given [absoluteUri], or `null` if the
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
302 } else { 363 } else {
303 if (combinator.names.contains(name)) { 364 if (combinator.names.contains(name)) {
304 return false; 365 return false;
305 } 366 }
306 } 367 }
307 } 368 }
308 return true; 369 return true;
309 } 370 }
310 } 371 }
311 372
373 /// The char range of a function body.
374 class _BodyRange {
375 /// The char offset of the first token in the range.
376 final int first;
377
378 /// The char offset of the last token in the range.
379 final int last;
380
381 _BodyRange(this.first, this.last);
382
383 @override
384 String toString() => '[$first, $last]';
385 }
386
387 /// The [Parser] that skips function bodies and remembers their token ranges.
388 class _BodySkippingParser extends Parser {
389 final List<_BodyRange> bodyRanges = [];
390
391 _BodySkippingParser() : super(new Listener());
392
393 @override
394 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
395 if (identical('{', token.lexeme)) {
396 Token close = skipBlock(token);
397 bodyRanges.add(new _BodyRange(token.charOffset, close.charOffset));
398 return close;
399 }
400 return super.parseFunctionBody(token, isExpression, allowAbstract);
401 }
402 }
403
312 /// [DirectiveListener] that skips native clauses. 404 /// [DirectiveListener] that skips native clauses.
313 class _DirectiveListenerWithNative extends DirectiveListener { 405 class _DirectiveListenerWithNative extends DirectiveListener {
314 @override 406 @override
315 Token handleNativeClause(Token token) => skipNativeClause(token); 407 Token handleNativeClause(Token token) => skipNativeClause(token);
316 } 408 }
317 409
318 /// [FileSystemState] based implementation of [FileSystem]. 410 /// [FileSystemState] based implementation of [FileSystem].
319 /// It provides a consistent view on the known file system state. 411 /// It provides a consistent view on the known file system state.
320 class _FileSystemView implements FileSystem { 412 class _FileSystemView implements FileSystem {
321 final FileSystemState fsState; 413 final FileSystemState fsState;
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 node.isEvaluated = true; 490 node.isEvaluated = true;
399 cycle.libraries.add(node.file); 491 cycle.libraries.add(node.file);
400 } 492 }
401 topologicallySortedCycles.add(cycle); 493 topologicallySortedCycles.add(cycle);
402 } 494 }
403 495
404 _LibraryNode getNode(FileState file) { 496 _LibraryNode getNode(FileState file) {
405 return nodesOfFiles.putIfAbsent(file, () => new _LibraryNode(this, file)); 497 return nodesOfFiles.putIfAbsent(file, () => new _LibraryNode(this, file));
406 } 498 }
407 } 499 }
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