OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library dart2js_incremental.library_updater; | 5 library dart2js_incremental.library_updater; |
6 | 6 |
7 import 'dart:async' show | 7 import 'dart:async' show |
8 Future; | 8 Future; |
9 | 9 |
10 import 'dart:convert' show | 10 import 'dart:convert' show |
11 UTF8; | 11 UTF8; |
12 | 12 |
13 import 'package:compiler/compiler.dart' as api; | 13 import 'package:compiler/compiler.dart' as api; |
14 | 14 |
15 import 'package:compiler/implementation/dart2jslib.dart' show | 15 import 'package:compiler/implementation/dart2jslib.dart' show |
16 Compiler, | 16 Compiler, |
17 Script; | 17 Script; |
18 | 18 |
19 import 'package:compiler/implementation/elements/elements.dart' show | 19 import 'package:compiler/implementation/elements/elements.dart' show |
| 20 Element, |
20 LibraryElement; | 21 LibraryElement; |
21 | 22 |
22 import 'package:compiler/implementation/scanner/scannerlib.dart' show | 23 import 'package:compiler/implementation/scanner/scannerlib.dart' show |
23 EOF_TOKEN, | 24 EOF_TOKEN, |
24 PartialElement, | 25 PartialElement, |
25 PartialFunctionElement, | 26 PartialFunctionElement, |
26 Token; | 27 Token; |
27 | 28 |
28 import 'package:compiler/implementation/source_file.dart' show | 29 import 'package:compiler/implementation/source_file.dart' show |
29 StringSourceFile; | 30 StringSourceFile; |
(...skipping 15 matching lines...) Expand all Loading... |
45 final api.CompilerInputProvider inputProvider; | 46 final api.CompilerInputProvider inputProvider; |
46 | 47 |
47 final Logger logTime; | 48 final Logger logTime; |
48 | 49 |
49 final Logger logVerbose; | 50 final Logger logVerbose; |
50 | 51 |
51 // TODO(ahe): Get rid of this field. It assumes that only one library has | 52 // TODO(ahe): Get rid of this field. It assumes that only one library has |
52 // changed. | 53 // changed. |
53 final Uri uri; | 54 final Uri uri; |
54 | 55 |
| 56 // When [true], updates must be applied (using [applyUpdates]) before the |
| 57 // [compiler]'s state correctly reflects the updated program. |
| 58 bool hasPendingUpdates = false; |
| 59 |
55 final List<Update> updates = <Update>[]; | 60 final List<Update> updates = <Update>[]; |
56 | 61 |
57 LibraryUpdater( | 62 LibraryUpdater( |
58 this.compiler, | 63 this.compiler, |
59 this.inputProvider, | 64 this.inputProvider, |
60 this.uri, | 65 this.uri, |
61 this.logTime, | 66 this.logTime, |
62 this.logVerbose); | 67 this.logVerbose); |
63 | 68 |
64 /// Used as tear-off passed to [LibraryLoaderTask.resetAsync]. | 69 /// Used as tear-off passed to [LibraryLoaderTask.resetAsync]. |
65 Future<bool> reuseLibrary(LibraryElement library) { | 70 Future<bool> reuseLibrary(LibraryElement library) { |
66 assert(compiler != null); | 71 assert(compiler != null); |
67 if (library.isPlatformLibrary || library.isPackageLibrary) { | 72 if (library.isPlatformLibrary || library.isPackageLibrary) { |
68 logTime('Reusing $library.'); | 73 logTime('Reusing $library.'); |
69 return new Future.value(true); | 74 return new Future.value(true); |
70 } else if (library != compiler.mainApp) { | 75 } else if (library != compiler.mainApp) { |
71 return new Future.value(false); | 76 return new Future.value(false); |
72 } | 77 } |
73 return inputProvider(uri).then((List<int> bytes) { | 78 return inputProvider(uri).then((List<int> bytes) { |
74 if (canReuseLibrary(library, bytes)) { | 79 return canReuseLibrary(library, bytes); |
75 // TODO(ahe): Temporary. Since we don't yet apply the updates, the | |
76 // library cannot be reused if there are updates. | |
77 return updates.isEmpty; | |
78 } else { | |
79 return false; | |
80 } | |
81 }); | 80 }); |
82 } | 81 } |
83 | 82 |
84 /// Returns true if [library] can be reused. | 83 /// Returns true if [library] can be reused. |
85 /// | 84 /// |
86 /// This methods also computes the [updates] (patches) needed to have | 85 /// This methods also computes the [updates] (patches) needed to have |
87 /// [library] reflect the modifications in [bytes]. | 86 /// [library] reflect the modifications in [bytes]. |
88 bool canReuseLibrary(LibraryElement library, List<int> bytes) { | 87 bool canReuseLibrary(LibraryElement library, List<int> bytes) { |
89 logTime('Attempting to reuse mainApp.'); | 88 logTime('Attempting to reuse mainApp.'); |
90 String newSource = UTF8.decode(bytes); | 89 String newSource = UTF8.decode(bytes); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 | 129 |
131 if (before is PartialFunctionElement && after is PartialFunctionElement) { | 130 if (before is PartialFunctionElement && after is PartialFunctionElement) { |
132 if (!canReuseFunction(diffToken, before, after)) { | 131 if (!canReuseFunction(diffToken, before, after)) { |
133 return false; | 132 return false; |
134 } | 133 } |
135 } else { | 134 } else { |
136 // Unhandled kind of element. | 135 // Unhandled kind of element. |
137 return false; | 136 return false; |
138 } | 137 } |
139 } | 138 } |
| 139 hasPendingUpdates = true; |
140 | 140 |
141 return true; | 141 return true; |
142 } | 142 } |
143 | 143 |
144 /// Returns true if function [before] can be reused to reflect the changes in | 144 /// Returns true if function [before] can be reused to reflect the changes in |
145 /// [after]. | 145 /// [after]. |
146 /// | 146 /// |
147 /// If [before] can be reused, an update (patch) is added to [updates]. | 147 /// If [before] can be reused, an update (patch) is added to [updates]. |
148 bool canReuseFunction( | 148 bool canReuseFunction( |
149 Token diffToken, | 149 Token diffToken, |
(...skipping 14 matching lines...) Expand all Loading... |
164 if (token == diffToken) { | 164 if (token == diffToken) { |
165 logVerbose('Signature changed'); | 165 logVerbose('Signature changed'); |
166 return false; | 166 return false; |
167 } | 167 } |
168 token = token.next; | 168 token = token.next; |
169 } | 169 } |
170 print('Simple modification of ${after} detected'); | 170 print('Simple modification of ${after} detected'); |
171 updates.add(new FunctionUpdate(compiler, before, after)); | 171 updates.add(new FunctionUpdate(compiler, before, after)); |
172 return true; | 172 return true; |
173 } | 173 } |
| 174 |
| 175 List<Element> applyUpdates() { |
| 176 return updates.map((Update update) => update.apply()).toList(); |
| 177 } |
174 } | 178 } |
175 | 179 |
176 /// Represents an update (aka patch) of [before] to [after]. We use the word | 180 /// Represents an update (aka patch) of [before] to [after]. We use the word |
177 /// "update" to avoid confusion with the compiler feature of "patch" methods. | 181 /// "update" to avoid confusion with the compiler feature of "patch" methods. |
178 abstract class Update { | 182 abstract class Update { |
179 final Compiler compiler; | 183 final Compiler compiler; |
180 | 184 |
181 PartialElement get before; | 185 PartialElement get before; |
182 | 186 |
183 PartialElement get after; | 187 PartialElement get after; |
(...skipping 26 matching lines...) Expand all Loading... |
210 before.getOrSet = after.getOrSet; | 214 before.getOrSet = after.getOrSet; |
211 } | 215 } |
212 | 216 |
213 /// Reset various caches and remove this element from the compiler's internal | 217 /// Reset various caches and remove this element from the compiler's internal |
214 /// state. | 218 /// state. |
215 void reuseElement() { | 219 void reuseElement() { |
216 compiler.forgetElement(before); | 220 compiler.forgetElement(before); |
217 before.reuseElement(); | 221 before.reuseElement(); |
218 } | 222 } |
219 } | 223 } |
OLD | NEW |