Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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:convert' show UTF8; | 5 import 'dart:convert' show UTF8; |
| 6 import 'dart:core' hide Resource; | 6 import 'dart:core' hide Resource; |
| 7 | 7 |
| 8 import 'package:analyzer/dart/element/element.dart'; | 8 import 'package:analyzer/dart/element/element.dart'; |
| 9 import 'package:analyzer/file_system/file_system.dart'; | |
| 10 import 'package:analyzer/src/generated/engine.dart'; | 9 import 'package:analyzer/src/generated/engine.dart'; |
| 11 import 'package:analyzer/src/generated/source.dart'; | 10 import 'package:analyzer/src/generated/source.dart'; |
| 12 import 'package:analyzer/src/summary/format.dart'; | 11 import 'package:analyzer/src/summary/format.dart'; |
| 13 import 'package:analyzer/src/summary/idl.dart'; | 12 import 'package:analyzer/src/summary/idl.dart'; |
| 14 import 'package:analyzer/src/summary/summarize_elements.dart'; | 13 import 'package:analyzer/src/summary/summarize_elements.dart'; |
| 15 import 'package:crypto/crypto.dart'; | 14 import 'package:crypto/crypto.dart'; |
| 16 | 15 |
| 17 /** | 16 /** |
| 18 * Storage for cache data. | 17 * Storage for cache data. |
| 19 */ | 18 */ |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 30 * Otherwise the key-value pair is added to the storage. | 29 * Otherwise the key-value pair is added to the storage. |
| 31 * | 30 * |
| 32 * It is not guaranteed that data will always be accessible using [get], in | 31 * It is not guaranteed that data will always be accessible using [get], in |
| 33 * some implementations association may silently fail or become inaccessible | 32 * some implementations association may silently fail or become inaccessible |
| 34 * after some time. | 33 * after some time. |
| 35 */ | 34 */ |
| 36 void put(String key, List<int> bytes); | 35 void put(String key, List<int> bytes); |
| 37 } | 36 } |
| 38 | 37 |
| 39 /** | 38 /** |
| 40 * A [Folder] based implementation of [CacheStorage]. | |
| 41 */ | |
| 42 class FolderCacheStorage implements CacheStorage { | |
|
Paul Berry
2016/03/21 20:29:32
I'm not sure I agree with the idea of removing thi
scheglov
2016/03/21 20:58:26
OK, restored.
| |
| 43 /** | |
| 44 * The folder to read and write files. | |
| 45 */ | |
| 46 final Folder folder; | |
| 47 | |
| 48 /** | |
| 49 * To ensure that operations of writing files are atomic we create a temporary | |
| 50 * file with this name in the [folder] and then rename it once we are | |
| 51 * done writing. | |
| 52 */ | |
| 53 final String tempFileName; | |
| 54 | |
| 55 FolderCacheStorage(this.folder, this.tempFileName); | |
| 56 | |
| 57 @override | |
| 58 List<int> get(String key) { | |
| 59 Resource file = folder.getChild(key); | |
| 60 if (file is File) { | |
| 61 try { | |
| 62 return file.readAsBytesSync(); | |
| 63 } on FileSystemException {} | |
| 64 } | |
| 65 return null; | |
| 66 } | |
| 67 | |
| 68 @override | |
| 69 void put(String key, List<int> bytes) { | |
| 70 String absPath = folder.getChild(key).path; | |
| 71 File tempFile = folder.getChild(tempFileName); | |
| 72 tempFile.writeAsBytesSync(bytes); | |
| 73 try { | |
| 74 tempFile.renameSync(absPath); | |
| 75 } catch (e) {} | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * Cache of information to support incremental analysis. | 39 * Cache of information to support incremental analysis. |
| 81 * | 40 * |
| 82 * Note that currently this class is not intended for interactive use. | 41 * Note that currently this class is not intended for interactive use. |
| 83 */ | 42 */ |
| 84 class IncrementalCache { | 43 class IncrementalCache { |
| 85 /** | 44 /** |
| 86 * The storage for the cache data. | 45 * The storage for the cache data. |
| 87 */ | 46 */ |
| 88 final CacheStorage storage; | 47 final CacheStorage storage; |
| 89 | 48 |
| 90 /** | 49 /** |
| 91 * The context in which this cache is used. | 50 * The context in which this cache is used. |
| 92 */ | 51 */ |
| 93 final AnalysisContext context; | 52 final AnalysisContext context; |
| 94 | 53 |
| 95 /** | 54 /** |
| 96 * Opaque data that reflects the current configuration, such as the [context] | 55 * Opaque data that reflects the current configuration, such as the [context] |
| 97 * options, and is mixed into the hashes. | 56 * options, and is mixed into the hashes. |
| 98 */ | 57 */ |
| 99 final List<int> configSalt; | 58 final List<int> configSalt; |
| 100 | 59 |
| 101 final Map<Source, CacheSourceContent> _sourceContentMap = | 60 final Map<Source, CacheSourceContent> _sourceContentMap = |
| 102 <Source, CacheSourceContent>{}; | 61 <Source, CacheSourceContent>{}; |
| 103 final Map<Source, List<Source>> _libraryClosureMap = <Source, List<Source>>{}; | 62 final Map<Source, List<Source>> _libraryClosureMap = <Source, List<Source>>{}; |
| 63 final Map<Source, List<int>> _libraryClosureHashMap = <Source, List<int>>{}; | |
| 104 final Map<Source, List<int>> _sourceContentHashMap = <Source, List<int>>{}; | 64 final Map<Source, List<int>> _sourceContentHashMap = <Source, List<int>>{}; |
| 105 | 65 |
| 106 /** | 66 /** |
| 107 * Mapping from a library closure key to its [PackageBundle]. | 67 * Mapping from a library closure key to its [PackageBundle]. |
| 108 */ | 68 */ |
| 109 final Map<String, PackageBundle> _bundleMap = <String, PackageBundle>{}; | 69 final Map<String, PackageBundle> _bundleMap = <String, PackageBundle>{}; |
| 110 | 70 |
| 71 final Map<String, Source> _absoluteUriMap = <String, Source>{}; | |
| 72 | |
| 111 IncrementalCache(this.storage, this.context, this.configSalt); | 73 IncrementalCache(this.storage, this.context, this.configSalt); |
| 112 | 74 |
| 113 /** | 75 /** |
| 114 * Clear internal caches so that we read from file system again. | 76 * Clear internal caches so that we read from file system again. |
| 115 */ | 77 */ |
| 116 void clearInternalCaches() { | 78 void clearInternalCaches() { |
| 117 _sourceContentMap.clear(); | 79 _sourceContentMap.clear(); |
| 118 _libraryClosureMap.clear(); | 80 _libraryClosureMap.clear(); |
| 119 _sourceContentHashMap.clear(); | 81 _sourceContentHashMap.clear(); |
| 120 _bundleMap.clear(); | 82 _bundleMap.clear(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 131 * using [LibraryBundleWithId.id]. | 93 * using [LibraryBundleWithId.id]. |
| 132 */ | 94 */ |
| 133 List<LibraryBundleWithId> getLibraryClosureBundles(Source librarySource) { | 95 List<LibraryBundleWithId> getLibraryClosureBundles(Source librarySource) { |
| 134 try { | 96 try { |
| 135 List<Source> closureSources = _getLibraryClosure(librarySource); | 97 List<Source> closureSources = _getLibraryClosure(librarySource); |
| 136 List<LibraryBundleWithId> closureBundles = <LibraryBundleWithId>[]; | 98 List<LibraryBundleWithId> closureBundles = <LibraryBundleWithId>[]; |
| 137 for (Source source in closureSources) { | 99 for (Source source in closureSources) { |
| 138 if (source.isInSystemLibrary) { | 100 if (source.isInSystemLibrary) { |
| 139 continue; | 101 continue; |
| 140 } | 102 } |
| 103 if (getSourceKind(source) == SourceKind.PART) { | |
| 104 continue; | |
| 105 } | |
| 141 String key = _getLibraryBundleKey(source); | 106 String key = _getLibraryBundleKey(source); |
| 142 PackageBundle bundle = _getLibraryBundle(key); | 107 PackageBundle bundle = _getLibraryBundle(key); |
| 143 if (bundle == null) { | 108 if (bundle == null) { |
| 144 return null; | 109 return null; |
| 145 } | 110 } |
| 146 closureBundles.add(new LibraryBundleWithId(source, key, bundle)); | 111 closureBundles.add(new LibraryBundleWithId(source, key, bundle)); |
| 147 } | 112 } |
| 148 return closureBundles; | 113 return closureBundles; |
| 149 } catch (e) { | 114 } catch (e) { |
| 150 return null; | 115 return null; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 187 * all its directly or indirectly imported or exported libraries. | 152 * all its directly or indirectly imported or exported libraries. |
| 188 */ | 153 */ |
| 189 void _appendLibraryClosure(Set<Source> closure, Source librarySource) { | 154 void _appendLibraryClosure(Set<Source> closure, Source librarySource) { |
| 190 if (closure.add(librarySource)) { | 155 if (closure.add(librarySource)) { |
| 191 CacheSourceContent contentSource = _getCacheSourceContent(librarySource); | 156 CacheSourceContent contentSource = _getCacheSourceContent(librarySource); |
| 192 if (contentSource == null) { | 157 if (contentSource == null) { |
| 193 throw new StateError('No structure for $librarySource'); | 158 throw new StateError('No structure for $librarySource'); |
| 194 } | 159 } |
| 195 // Append parts. | 160 // Append parts. |
| 196 for (String partUri in contentSource.partUris) { | 161 for (String partUri in contentSource.partUris) { |
| 197 Source partSource = | 162 Source partSource = _resolveUri(librarySource, partUri); |
| 198 context.sourceFactory.resolveUri(librarySource, partUri); | |
| 199 if (partSource == null) { | 163 if (partSource == null) { |
| 200 throw new StateError('Unable to resolve $partUri in $librarySource'); | 164 throw new StateError('Unable to resolve $partUri in $librarySource'); |
| 201 } | 165 } |
| 202 closure.add(partSource); | 166 closure.add(partSource); |
| 203 } | 167 } |
| 204 // Append imports and exports. | 168 // Append imports and exports. |
| 205 void appendLibrarySources(String refUri) { | 169 void appendLibrarySources(String refUri) { |
| 206 Source refSource = | 170 Source refSource = _resolveUri(librarySource, refUri); |
| 207 context.sourceFactory.resolveUri(librarySource, refUri); | |
| 208 if (refSource == null) { | 171 if (refSource == null) { |
| 209 throw new StateError('Unable to resolve $refUri in $librarySource'); | 172 throw new StateError('Unable to resolve $refUri in $librarySource'); |
| 210 } | 173 } |
| 211 _appendLibraryClosure(closure, refSource); | 174 _appendLibraryClosure(closure, refSource); |
| 212 } | 175 } |
| 213 contentSource.importedUris.forEach(appendLibrarySources); | 176 contentSource.importedUris.forEach(appendLibrarySources); |
| 214 contentSource.exportedUris.forEach(appendLibrarySources); | 177 contentSource.exportedUris.forEach(appendLibrarySources); |
| 215 } | 178 } |
| 216 } | 179 } |
| 217 | 180 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 278 _appendLibraryClosure(closure, librarySource); | 241 _appendLibraryClosure(closure, librarySource); |
| 279 return closure.toList(); | 242 return closure.toList(); |
| 280 }); | 243 }); |
| 281 } | 244 } |
| 282 | 245 |
| 283 /** | 246 /** |
| 284 * Return the [context]-specific hash of the closure of the library with | 247 * Return the [context]-specific hash of the closure of the library with |
| 285 * the given [librarySource]. | 248 * the given [librarySource]. |
| 286 */ | 249 */ |
| 287 List<int> _getLibraryClosureHash(Source librarySource) { | 250 List<int> _getLibraryClosureHash(Source librarySource) { |
| 288 List<Source> closure = _getLibraryClosure(librarySource); | 251 return _libraryClosureHashMap.putIfAbsent(librarySource, () { |
| 289 MD5 md5 = new MD5(); | 252 List<Source> closure = _getLibraryClosure(librarySource); |
| 290 for (Source source in closure) { | 253 MD5 md5 = new MD5(); |
| 291 List<int> sourceHash = _getSourceContentHash(source); | 254 for (Source source in closure) { |
| 292 md5.add(sourceHash); | 255 List<int> sourceHash = _getSourceContentHash(source); |
| 293 } | 256 md5.add(sourceHash); |
| 294 md5.add(configSalt); | 257 } |
| 295 return md5.close(); | 258 md5.add(configSalt); |
| 259 return md5.close(); | |
| 260 }); | |
| 296 } | 261 } |
| 297 | 262 |
| 298 /** | 263 /** |
| 299 * Compute a hash of the given [source] contents. | 264 * Compute a hash of the given [source] contents. |
| 300 */ | 265 */ |
| 301 List<int> _getSourceContentHash(Source source) { | 266 List<int> _getSourceContentHash(Source source) { |
| 302 return _sourceContentHashMap.putIfAbsent(source, () { | 267 return _sourceContentHashMap.putIfAbsent(source, () { |
| 303 String sourceText = source.contents.data; | 268 String sourceText = source.contents.data; |
| 304 List<int> sourceBytes = UTF8.encode(sourceText); | 269 List<int> sourceBytes = UTF8.encode(sourceText); |
| 305 return (new MD5()..add(sourceBytes)).close(); | 270 return (new MD5()..add(sourceBytes)).close(); |
| 306 }); | 271 }); |
| 307 } | 272 } |
| 308 | 273 |
| 309 /** | 274 /** |
| 275 * Return a source representing the URI that results from resolving the given | |
| 276 * (possibly relative) [containedUri] against the URI associated with the | |
| 277 * [containingSource], whether or not the resulting source exists, or `null` | |
| 278 * if either the [containedUri] is invalid or if it cannot be resolved against | |
| 279 * the [containingSource]'s URI. | |
| 280 */ | |
| 281 Source _resolveUri(Source containingSource, String containedUri) { | |
| 282 // Cache absolute URIs. | |
| 283 if (containedUri.startsWith('dart:') || | |
|
Paul Berry
2016/03/21 20:29:32
If the goal is to figure out whether this is an ab
scheglov
2016/03/21 20:58:26
See the performance results in mail.
URI operation
| |
| 284 containedUri.startsWith('package:')) { | |
| 285 return _absoluteUriMap.putIfAbsent(containedUri, () { | |
| 286 return context.sourceFactory.resolveUri(containingSource, containedUri); | |
| 287 }); | |
| 288 } | |
| 289 // Resolve relative URIs without caching. | |
| 290 return context.sourceFactory.resolveUri(containingSource, containedUri); | |
| 291 } | |
| 292 | |
| 293 /** | |
| 310 * Write the content based information about the given [source]. | 294 * Write the content based information about the given [source]. |
| 311 */ | 295 */ |
| 312 void _writeCacheSourceContent(Source source, CacheSourceContentBuilder b) { | 296 void _writeCacheSourceContent(Source source, CacheSourceContentBuilder b) { |
| 313 String key = _getCacheSourceContentKey(source); | 297 String key = _getCacheSourceContentKey(source); |
| 314 List<int> bytes = b.toBuffer(); | 298 List<int> bytes = b.toBuffer(); |
| 315 storage.put(key, bytes); | 299 storage.put(key, bytes); |
| 316 // Put into the cache to avoid reading it later. | 300 // Put into the cache to avoid reading it later. |
| 317 _sourceContentMap[source] = new CacheSourceContent.fromBuffer(bytes); | 301 _sourceContentMap[source] = new CacheSourceContent.fromBuffer(bytes); |
| 318 } | 302 } |
| 319 | 303 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 386 */ | 370 */ |
| 387 final String id; | 371 final String id; |
| 388 | 372 |
| 389 /** | 373 /** |
| 390 * The payload bundle. | 374 * The payload bundle. |
| 391 */ | 375 */ |
| 392 final PackageBundle bundle; | 376 final PackageBundle bundle; |
| 393 | 377 |
| 394 LibraryBundleWithId(this.source, this.id, this.bundle); | 378 LibraryBundleWithId(this.source, this.id, this.bundle); |
| 395 } | 379 } |
| OLD | NEW |