Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/incremental_kernel_generator.dart'; | 7 import 'package:front_end/incremental_kernel_generator.dart'; |
| 8 import 'package:front_end/src/base/performace_logger.dart'; | 8 import 'package:front_end/src/base/performace_logger.dart'; |
| 9 import 'package:front_end/src/base/processed_options.dart'; | 9 import 'package:front_end/src/base/processed_options.dart'; |
| 10 import 'package:front_end/src/fasta/uri_translator.dart'; | 10 import 'package:front_end/src/fasta/uri_translator.dart'; |
| 11 import 'package:front_end/src/incremental/file_state.dart'; | 11 import 'package:front_end/src/incremental/file_state.dart'; |
| 12 import 'package:front_end/src/incremental/kernel_driver.dart'; | 12 import 'package:front_end/src/incremental/kernel_driver.dart'; |
| 13 import 'package:kernel/kernel.dart' hide Source; | 13 import 'package:kernel/kernel.dart' hide Source; |
| 14 import 'package:meta/meta.dart'; | 14 import 'package:meta/meta.dart'; |
| 15 | 15 |
| 16 /// Implementation of [IncrementalKernelGenerator]. | 16 /// Implementation of [IncrementalKernelGenerator]. |
| 17 /// | 17 /// |
| 18 /// TODO(scheglov) Update the documentation. | 18 /// TODO(scheglov) Update the documentation. |
| 19 /// | 19 /// |
| 20 /// Theory of operation: an instance of [IncrementalResolvedAstGenerator] is | 20 /// Theory of operation: an instance of [IncrementalResolvedAstGenerator] is |
| 21 /// used to obtain resolved ASTs, and these are fed into kernel code generation | 21 /// used to obtain resolved ASTs, and these are fed into kernel code generation |
| 22 /// logic. | 22 /// logic. |
| 23 class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator { | 23 class IncrementalKernelGeneratorImpl implements IncrementalKernelGenerator { |
| 24 /// The version of data format, should be incremented on every format change. | 24 static const MSG_PENDING_COMPUTE = |
|
Siggi Cherem (dart-lang)
2017/08/11 00:44:52
not for this CL: even if we don't report them on t
scheglov
2017/08/11 04:50:40
Yes, is seems like it might be useful to put into
| |
| 25 static const int DATA_VERSION = 1; | 25 'Another computeDelta() invocation is still executing.'; |
|
Siggi Cherem (dart-lang)
2017/08/11 00:44:52
Consider: Another => A
(since now this message is
scheglov
2017/08/11 04:50:40
Done.
| |
| 26 | |
| 27 static const MSG_NO_LAST_DELTA = | |
| 28 'The last delta has been already accepted or rejected.'; | |
| 29 | |
| 30 static const MSG_HAS_LAST_DELTA = | |
| 31 'The last delta must be either accepted or rejected.'; | |
| 26 | 32 |
| 27 /// The logger to report compilation progress. | 33 /// The logger to report compilation progress. |
| 28 final PerformanceLog _logger; | 34 final PerformanceLog _logger; |
| 29 | 35 |
| 30 /// The URI of the program entry point. | 36 /// The URI of the program entry point. |
| 31 final Uri _entryPoint; | 37 final Uri _entryPoint; |
| 32 | 38 |
| 33 /// The function to notify when files become used or unused, or `null`. | 39 /// The function to notify when files become used or unused, or `null`. |
| 34 final WatchUsedFilesFn _watchFn; | 40 final WatchUsedFilesFn _watchFn; |
| 35 | 41 |
| 36 /// The [KernelDriver] that is used to compute kernels. | 42 /// The [KernelDriver] that is used to compute kernels. |
| 37 KernelDriver _driver; | 43 KernelDriver _driver; |
| 38 | 44 |
| 45 /// Whether [computeDelta] is executing. | |
| 46 bool _isComputeDeltaExecuting = false; | |
| 47 | |
| 39 /// The current signatures for libraries. | 48 /// The current signatures for libraries. |
| 40 final Map<Uri, String> _currentSignatures = {}; | 49 final Map<Uri, String> _currentSignatures = {}; |
| 41 | 50 |
| 42 /// The signatures for libraries produced by the last [computeDelta], or | 51 /// The signatures for libraries produced by the last [computeDelta], or |
| 43 /// `null` if the last delta was either accepted or rejected. | 52 /// `null` if the last delta was either accepted or rejected. |
| 44 Map<Uri, String> _lastSignatures; | 53 Map<Uri, String> _lastSignatures; |
| 45 | 54 |
| 46 /// The object that provides additional information for tests. | 55 /// The object that provides additional information for tests. |
| 47 _TestView _testView; | 56 _TestView _testView; |
| 48 | 57 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 69 _TestView get test => _testView; | 78 _TestView get test => _testView; |
| 70 | 79 |
| 71 @override | 80 @override |
| 72 void acceptLastDelta() { | 81 void acceptLastDelta() { |
| 73 _throwIfNoLastDelta(); | 82 _throwIfNoLastDelta(); |
| 74 _currentSignatures.addAll(_lastSignatures); | 83 _currentSignatures.addAll(_lastSignatures); |
| 75 _lastSignatures = null; | 84 _lastSignatures = null; |
| 76 } | 85 } |
| 77 | 86 |
| 78 @override | 87 @override |
| 79 Future<DeltaProgram> computeDelta() async { | 88 Future<DeltaProgram> computeDelta() { |
| 89 if (_isComputeDeltaExecuting) { | |
| 90 throw new StateError(MSG_PENDING_COMPUTE); | |
| 91 } | |
| 92 | |
| 80 if (_lastSignatures != null) { | 93 if (_lastSignatures != null) { |
| 81 throw new StateError( | 94 throw new StateError(MSG_HAS_LAST_DELTA); |
| 82 'The last delta must be either accepted or rejected.'); | |
| 83 } | 95 } |
| 84 _lastSignatures = {}; | 96 _lastSignatures = {}; |
| 85 | 97 |
| 86 return await _logger.runAsync('Compute delta', () async { | 98 _isComputeDeltaExecuting = true; |
| 87 KernelResult kernelResult = await _driver.getKernel(_entryPoint); | |
| 88 List<LibraryCycleResult> results = kernelResult.results; | |
| 89 | 99 |
| 90 // The file graph might have changed, perform GC. | 100 return _logger.runAsync('Compute delta', () async { |
| 91 await _gc(); | 101 try { |
| 102 KernelResult kernelResult = await _driver.getKernel(_entryPoint); | |
| 103 List<LibraryCycleResult> results = kernelResult.results; | |
| 92 | 104 |
| 93 // The set of affected library cycles (have different signatures). | 105 // The file graph might have changed, perform GC. |
| 94 final affectedLibraryCycles = new Set<LibraryCycle>(); | 106 await _gc(); |
| 95 for (LibraryCycleResult result in results) { | 107 |
| 96 for (Library library in result.kernelLibraries) { | 108 // The set of affected library cycles (have different signatures). |
| 97 Uri uri = library.importUri; | 109 final affectedLibraryCycles = new Set<LibraryCycle>(); |
| 98 if (_currentSignatures[uri] != result.signature) { | 110 for (LibraryCycleResult result in results) { |
| 99 _lastSignatures[uri] = result.signature; | 111 for (Library library in result.kernelLibraries) { |
| 100 affectedLibraryCycles.add(result.cycle); | 112 Uri uri = library.importUri; |
| 113 if (_currentSignatures[uri] != result.signature) { | |
| 114 _lastSignatures[uri] = result.signature; | |
| 115 affectedLibraryCycles.add(result.cycle); | |
| 116 } | |
| 101 } | 117 } |
| 102 } | 118 } |
| 103 } | |
| 104 | 119 |
| 105 // The set of affected library cycles (have different signatures), | 120 // The set of affected library cycles (have different signatures), |
| 106 // or libraries that import or export affected libraries (so VM might | 121 // or libraries that import or export affected libraries (so VM might |
| 107 // have inlined some code from affected libraries into them). | 122 // have inlined some code from affected libraries into them). |
| 108 final vmRequiredLibraryCycles = new Set<LibraryCycle>(); | 123 final vmRequiredLibraryCycles = new Set<LibraryCycle>(); |
| 109 | 124 |
| 110 void gatherVmRequiredLibraryCycles(LibraryCycle cycle) { | 125 void gatherVmRequiredLibraryCycles(LibraryCycle cycle) { |
| 111 if (vmRequiredLibraryCycles.add(cycle)) { | 126 if (vmRequiredLibraryCycles.add(cycle)) { |
| 112 cycle.directUsers.forEach(gatherVmRequiredLibraryCycles); | 127 cycle.directUsers.forEach(gatherVmRequiredLibraryCycles); |
| 113 } | |
| 114 } | |
| 115 | |
| 116 affectedLibraryCycles.forEach(gatherVmRequiredLibraryCycles); | |
| 117 | |
| 118 // Add required libraries. | |
| 119 Program program = new Program(nameRoot: kernelResult.nameRoot); | |
| 120 for (LibraryCycleResult result in results) { | |
| 121 if (vmRequiredLibraryCycles.contains(result.cycle)) { | |
| 122 for (Library library in result.kernelLibraries) { | |
| 123 program.libraries.add(library); | |
| 124 library.parent = program; | |
| 125 } | 128 } |
| 126 } | 129 } |
| 127 } | |
| 128 | 130 |
| 129 // Set the main method. | 131 affectedLibraryCycles.forEach(gatherVmRequiredLibraryCycles); |
| 130 if (program.libraries.isNotEmpty) { | 132 |
| 131 for (Library library in results.last.kernelLibraries) { | 133 // Add required libraries. |
| 132 if (library.importUri == _entryPoint) { | 134 Program program = new Program(nameRoot: kernelResult.nameRoot); |
| 133 program.mainMethod = library.procedures.firstWhere( | 135 for (LibraryCycleResult result in results) { |
| 134 (procedure) => procedure.name.name == 'main', | 136 if (vmRequiredLibraryCycles.contains(result.cycle)) { |
| 135 orElse: () => null); | 137 for (Library library in result.kernelLibraries) { |
| 136 break; | 138 program.libraries.add(library); |
| 139 library.parent = program; | |
| 140 } | |
| 137 } | 141 } |
| 138 } | 142 } |
| 143 | |
| 144 // Set the main method. | |
| 145 if (program.libraries.isNotEmpty) { | |
| 146 for (Library library in results.last.kernelLibraries) { | |
| 147 if (library.importUri == _entryPoint) { | |
| 148 program.mainMethod = library.procedures.firstWhere( | |
| 149 (procedure) => procedure.name.name == 'main', | |
| 150 orElse: () => null); | |
| 151 break; | |
| 152 } | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 return new DeltaProgram(program); | |
| 157 } finally { | |
| 158 _isComputeDeltaExecuting = false; | |
| 139 } | 159 } |
| 140 | |
| 141 return new DeltaProgram(program); | |
| 142 }); | 160 }); |
| 143 } | 161 } |
| 144 | 162 |
| 145 @override | 163 @override |
| 146 void invalidate(Uri uri) { | 164 void invalidate(Uri uri) { |
| 147 _driver.invalidate(uri); | 165 _driver.invalidate(uri); |
| 148 } | 166 } |
| 149 | 167 |
| 150 @override | 168 @override |
| 151 void rejectLastDelta() { | 169 void rejectLastDelta() { |
| 152 _throwIfNoLastDelta(); | 170 _throwIfNoLastDelta(); |
| 153 _lastSignatures = null; | 171 _lastSignatures = null; |
| 154 } | 172 } |
| 155 | 173 |
| 156 /// TODO(scheglov) document | 174 /// Find files which are not referenced from the entry point and report |
| 175 /// them to the watch function. | |
| 157 Future<Null> _gc() async { | 176 Future<Null> _gc() async { |
| 158 var removedFiles = _driver.fsState.gc(_entryPoint); | 177 var removedFiles = _driver.fsState.gc(_entryPoint); |
| 159 if (removedFiles.isNotEmpty && _watchFn != null) { | 178 if (removedFiles.isNotEmpty && _watchFn != null) { |
| 160 for (var removedFile in removedFiles) { | 179 for (var removedFile in removedFiles) { |
| 161 await _watchFn(removedFile.fileUri, false); | 180 await _watchFn(removedFile.fileUri, false); |
| 162 } | 181 } |
| 163 } | 182 } |
| 164 } | 183 } |
| 165 | 184 |
| 166 /// Throw [StateError] if [_lastSignatures] is `null`, i.e. there is no | 185 /// Throw [StateError] if [_lastSignatures] is `null`, i.e. there is no |
| 167 /// last delta - it either has not been computed yet, or has been already | 186 /// last delta - it either has not been computed yet, or has been already |
| 168 /// accepted or rejected. | 187 /// accepted or rejected. |
| 169 void _throwIfNoLastDelta() { | 188 void _throwIfNoLastDelta() { |
| 189 if (_isComputeDeltaExecuting) { | |
| 190 throw new StateError(MSG_PENDING_COMPUTE); | |
| 191 } | |
| 170 if (_lastSignatures == null) { | 192 if (_lastSignatures == null) { |
| 171 throw new StateError( | 193 throw new StateError(MSG_NO_LAST_DELTA); |
| 172 'The last delta has been already accepted or rejected.'); | |
| 173 } | 194 } |
| 174 } | 195 } |
| 175 } | 196 } |
| 176 | 197 |
| 177 @visibleForTesting | 198 @visibleForTesting |
| 178 class _TestView { | 199 class _TestView { |
| 179 final IncrementalKernelGeneratorImpl _generator; | 200 final IncrementalKernelGeneratorImpl _generator; |
| 180 | 201 |
| 181 _TestView(this._generator); | 202 _TestView(this._generator); |
| 182 | 203 |
| 183 /// The [KernelDriver] that is used to actually compile. | 204 /// The [KernelDriver] that is used to actually compile. |
| 184 KernelDriver get driver => _generator._driver; | 205 KernelDriver get driver => _generator._driver; |
| 185 } | 206 } |
| OLD | NEW |