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

Side by Side Diff: dart/pkg/dart2js_incremental/lib/library_updater.dart

Issue 701133003: Implement removal of overridden instance methods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Updated to work with r41550. Created 6 years, 1 month 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 | Annotate | Revision Log
OLDNEW
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/src/dart2jslib.dart' show 15 import 'package:compiler/src/dart2jslib.dart' show
16 Compiler, 16 Compiler,
17 Script; 17 Script;
18 18
19 import 'package:compiler/src/elements/elements.dart' show 19 import 'package:compiler/src/elements/elements.dart' show
20 ClassElement,
20 Element, 21 Element,
21 FunctionElement, 22 FunctionElement,
22 LibraryElement, 23 LibraryElement,
23 ScopeContainerElement; 24 ScopeContainerElement;
24 25
25 import 'package:compiler/src/scanner/scannerlib.dart' show 26 import 'package:compiler/src/scanner/scannerlib.dart' show
26 EOF_TOKEN, 27 EOF_TOKEN,
27 PartialClassElement, 28 PartialClassElement,
28 PartialElement, 29 PartialElement,
29 PartialFunctionElement, 30 PartialFunctionElement,
(...skipping 16 matching lines...) Expand all
46 CodeEmitterTask, 47 CodeEmitterTask,
47 MemberInfo; 48 MemberInfo;
48 49
49 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' 50 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart'
50 as embeddedNames; 51 as embeddedNames;
51 52
52 import 'package:compiler/src/js_backend/js_backend.dart' show 53 import 'package:compiler/src/js_backend/js_backend.dart' show
53 JavaScriptBackend, 54 JavaScriptBackend,
54 Namer; 55 Namer;
55 56
57 import 'package:compiler/src/util/util.dart' show
58 Link;
59
60 import 'package:compiler/src/elements/modelx.dart' show
61 DeclarationSite,
62 ElementX;
63
56 import 'diff.dart' show 64 import 'diff.dart' show
57 Difference, 65 Difference,
58 computeDifference; 66 computeDifference;
59 67
60 typedef void Logger(message); 68 typedef void Logger(message);
61 69
62 typedef bool Reuser( 70 typedef bool Reuser(
63 Token diffToken, 71 Token diffToken,
64 PartialElement before, 72 PartialElement before,
65 PartialElement after); 73 PartialElement after);
(...skipping 23 matching lines...) Expand all
89 final Logger logVerbose; 97 final Logger logVerbose;
90 98
91 // TODO(ahe): Get rid of this field. It assumes that only one library has 99 // TODO(ahe): Get rid of this field. It assumes that only one library has
92 // changed. 100 // changed.
93 final Uri uri; 101 final Uri uri;
94 102
95 final List<Update> updates = <Update>[]; 103 final List<Update> updates = <Update>[];
96 104
97 final List<FailedUpdate> _failedUpdates = <FailedUpdate>[]; 105 final List<FailedUpdate> _failedUpdates = <FailedUpdate>[];
98 106
107 final Set<ElementX> _elementsToInvalidate = new Set<ElementX>();
108
99 LibraryUpdater( 109 LibraryUpdater(
100 this.compiler, 110 this.compiler,
101 this.inputProvider, 111 this.inputProvider,
102 this.uri, 112 this.uri,
103 this.logTime, 113 this.logTime,
104 this.logVerbose); 114 this.logVerbose);
105 115
106 /// When [true], updates must be applied (using [applyUpdates]) before the 116 /// When [true], updates must be applied (using [applyUpdates]) before the
107 /// [compiler]'s state correctly reflects the updated program. 117 /// [compiler]'s state correctly reflects the updated program.
108 bool get hasPendingUpdates => !updates.isEmpty; 118 bool get hasPendingUpdates => !updates.isEmpty;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
162 return false; 172 return false;
163 } 173 }
164 174
165 bool canReuseScopeContainerElement( 175 bool canReuseScopeContainerElement(
166 ScopeContainerElement element, 176 ScopeContainerElement element,
167 ScopeContainerElement newElement) { 177 ScopeContainerElement newElement) {
168 List<Difference> differences = computeDifference(element, newElement); 178 List<Difference> differences = computeDifference(element, newElement);
169 logTime('Differences computed.'); 179 logTime('Differences computed.');
170 for (Difference difference in differences) { 180 for (Difference difference in differences) {
171 logTime('Looking at difference: $difference'); 181 logTime('Looking at difference: $difference');
172 if (difference.before == null || difference.after == null) { 182
173 cannotReuse(difference, "Can't reuse; Scope changed."); 183 if (difference.before == null && difference.after is PartialElement) {
184 canReuseAddedElement(difference.after);
185 continue;
186 }
187 if (difference.after == null && difference.before is PartialElement) {
188 canReuseRemovedElement(difference.before);
174 continue; 189 continue;
175 } 190 }
176 Token diffToken = difference.token; 191 Token diffToken = difference.token;
177 if (diffToken == null) { 192 if (diffToken == null) {
178 cannotReuse(difference, "No difference token."); 193 cannotReuse(difference, "No difference token.");
179 continue; 194 continue;
180 } 195 }
181 if (difference.after is! PartialElement && 196 if (difference.after is! PartialElement &&
182 difference.before is! PartialElement) { 197 difference.before is! PartialElement) {
183 cannotReuse(difference, "Don't know how to recompile."); 198 cannotReuse(difference, "Don't know how to recompile.");
(...skipping 14 matching lines...) Expand all
198 } 213 }
199 if (!reuser(diffToken, before, after)) { 214 if (!reuser(diffToken, before, after)) {
200 assert(!_failedUpdates.isEmpty); 215 assert(!_failedUpdates.isEmpty);
201 continue; 216 continue;
202 } 217 }
203 } 218 }
204 219
205 return _failedUpdates.isEmpty; 220 return _failedUpdates.isEmpty;
206 } 221 }
207 222
223 bool canReuseAddedElement(PartialElement element) {
224 return cannotReuse(element, "Scope changed, element added.");
225 }
226
227 bool canReuseRemovedElement(PartialElement element) {
228 if (element is PartialFunctionElement) {
229 return canReuseRemovedFunction(element);
230 }
231 return cannotReuse(
232 element, "Removed element that isn't a method.");
233 }
234
235 bool canReuseRemovedFunction(PartialFunctionElement element) {
236 if (!element.isInstanceMember) {
237 return cannotReuse(
238 element, "Removed function that isn't an instance method.");
239 }
240 logVerbose("Removed instance method $element.");
241
242 PartialClassElement cls = element.enclosingClass;
243 for (ScopeContainerElement scope in scopesAffectedBy(element, cls)) {
244 scanSites(scope, (Element member, DeclarationSite site) {
245 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior.
246 Map<String, List<String>> names = qualifiedNamesIn(site);
247 if (canNamesResolveTo(names, element, cls)) {
248 _elementsToInvalidate.add(member);
249 }
250 });
251 }
252
253 // TODO(ahe): Don't modify the class here, instead use an instance of
254 // Update.
255 Link<Element> localMembersReversed = const Link<Element>();
256 cls.forEachLocalMember((member) {
257 if (member != element) {
258 localMembersReversed = localMembersReversed.prepend(member);
259 }
260 });
261 cls.localMembersCache = null;
262 cls.localMembersReversed = localMembersReversed;
263 cls.localScope.contents.remove(element.name);
264
265 // TODO(ahe): Also compute a patch which removes the function, e.g.,
266 // "delete GlobalObject.MyClass.prototype.memberName".
267
268 // TODO(ahe): Also forget [element].
269
270 return true;
271 }
272
273 void scanSites(
274 Element element,
275 void f(ElementX element, DeclarationSite site)) {
276 DeclarationSite site = declarationSite(element);
277 if (site != null) {
278 f(element, site);
279 }
280 if (element is ScopeContainerElement) {
281 element.forEachLocalMember((member) { scanSites(member, f); });
282 }
283 }
284
285 List<ScopeContainerElement> scopesAffectedBy(
286 Element element,
287 ClassElement cls) {
288 // TODO(ahe): Use library export graph to compute this.
289 // TODO(ahe): Should return all user-defined libraries and packages.
290 LibraryElement library = element.library;
291 List<ScopeContainerElement> result = <ScopeContainerElement>[library];
292
293 if (cls == null) return result;
294
295 var externalSubtypes =
296 compiler.world.subtypesOf(cls).where((e) => e.library != library);
297
298 return result..addAll(externalSubtypes);
299 }
300
208 /// Returns true if function [before] can be reused to reflect the changes in 301 /// Returns true if function [before] can be reused to reflect the changes in
209 /// [after]. 302 /// [after].
210 /// 303 ///
211 /// If [before] can be reused, an update (patch) is added to [updates]. 304 /// If [before] can be reused, an update (patch) is added to [updates].
212 bool canReuseFunction( 305 bool canReuseFunction(
213 Token diffToken, 306 Token diffToken,
214 PartialFunctionElement before, 307 PartialFunctionElement before,
215 PartialFunctionElement after) { 308 PartialFunctionElement after) {
216 FunctionExpression node = 309 FunctionExpression node =
217 after.parseNode(compiler).asFunctionExpression(); 310 after.parseNode(compiler).asFunctionExpression();
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 after, 361 after,
269 'Unhandled change:' 362 'Unhandled change:'
270 ' ${before} (${before.runtimeType} -> ${after.runtimeType}).'); 363 ' ${before} (${before.runtimeType} -> ${after.runtimeType}).');
271 } 364 }
272 365
273 List<Element> applyUpdates() { 366 List<Element> applyUpdates() {
274 if (!_failedUpdates.isEmpty) { 367 if (!_failedUpdates.isEmpty) {
275 throw new StateError( 368 throw new StateError(
276 "Can't compute update.\n\n${_failedUpdates.join('\n\n')}"); 369 "Can't compute update.\n\n${_failedUpdates.join('\n\n')}");
277 } 370 }
278 return updates.map((Update update) => update.apply()).toList(); 371 for (ElementX element in _elementsToInvalidate) {
372 compiler.forgetElement(element);
373 element.reuseElement();
374 }
375 return updates.map((Update update) => update.apply()).toList()
376 ..addAll(_elementsToInvalidate);
279 } 377 }
280 378
281 String computeUpdateJs() { 379 String computeUpdateJs() {
282 List<Element> updatedElements = applyUpdates(); 380 List<Element> updatedElements = applyUpdates();
283 if (compiler.progress != null) { 381 if (compiler.progress != null) {
284 compiler.progress.reset(); 382 compiler.progress.reset();
285 } 383 }
286 for (Element element in updatedElements) { 384 for (Element element in updatedElements) {
287 compiler.enqueuer.resolution.addToWorkList(element); 385 compiler.enqueuer.resolution.addToWorkList(element);
288 } 386 }
(...skipping 26 matching lines...) Expand all
315 if (info == null) { 413 if (info == null) {
316 compiler.internalError(element, '${element.runtimeType}'); 414 compiler.internalError(element, '${element.runtimeType}');
317 } 415 }
318 String name = info.name; 416 String name = info.name;
319 jsAst.Node function = info.code; 417 jsAst.Node function = info.code;
320 List<jsAst.Statement> statements = <jsAst.Statement>[]; 418 List<jsAst.Statement> statements = <jsAst.Statement>[];
321 if (element.isInstanceMember) { 419 if (element.isInstanceMember) {
322 jsAst.Node elementAccess = namer.elementAccess(element.enclosingClass); 420 jsAst.Node elementAccess = namer.elementAccess(element.enclosingClass);
323 statements.add( 421 statements.add(
324 js.statement('#.prototype.# = f', [elementAccess, name])); 422 js.statement('#.prototype.# = f', [elementAccess, name]));
423
424 if (backend.isAliasedSuperMember(element)) {
425 String superName = namer.getNameOfAliasedSuperMember(element);
426 statements.add(
427 js.statement('#.prototype.# = f', [elementAccess, superName]));
ahe 2014/11/10 16:53:27 Stephan, does this look reasonable?
herhut 2014/11/13 10:55:08 Looks good.
428 }
325 } else { 429 } else {
326 jsAst.Node elementAccess = namer.elementAccess(element); 430 jsAst.Node elementAccess = namer.elementAccess(element);
327 jsAst.Expression globalFunctionsAccess = 431 jsAst.Expression globalFunctionsAccess =
328 emitter.generateEmbeddedGlobalAccess(embeddedNames.GLOBAL_FUNCTIONS); 432 emitter.generateEmbeddedGlobalAccess(embeddedNames.GLOBAL_FUNCTIONS);
329 statements.add( 433 statements.add(
330 js.statement( 434 js.statement(
331 '#.# = # = f', 435 '#.# = # = f',
332 [globalFunctionsAccess, name, elementAccess])); 436 [globalFunctionsAccess, name, elementAccess]));
333 if (info.canTearOff) { 437 if (info.canTearOff) {
334 String globalName = namer.globalObjectFor(element); 438 String globalName = namer.globalObjectFor(element);
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
396 before.getOrSet = after.getOrSet; 500 before.getOrSet = after.getOrSet;
397 } 501 }
398 502
399 /// Reset various caches and remove this element from the compiler's internal 503 /// Reset various caches and remove this element from the compiler's internal
400 /// state. 504 /// state.
401 void reuseElement() { 505 void reuseElement() {
402 compiler.forgetElement(before); 506 compiler.forgetElement(before);
403 before.reuseElement(); 507 before.reuseElement();
404 } 508 }
405 } 509 }
510
511 Map<String, List<String>> qualifiedNamesIn(PartialElement element) {
512 Token beginToken = element.beginToken;
513 Token endToken = element.endToken;
514 Token token = beginToken;
515 if (element is PartialClassElement) {
516 ClassNode node = element.cachedNode;
517 if (node != null) {
518 NodeList body = node.body;
519 if (body != null) {
520 endToken = body.beginToken;
521 }
522 }
523 }
524 Map<String, List<String>> names = new Map<String, List<String>>();
525 List<List<Token>> qualifieds = <List<Token>>[];
526 do {
527 if (token.isIdentifier()) {
528 List<String> name = names.putIfAbsent(token.value, () => <String>[]);
529 while (identical('.', token.next.stringValue) &&
530 token.next.next.isIdentifier()) {
531 token = token.next.next;
532 name.add(token.value);
533 }
534 }
535 token = token.next;
536 } while (token.kind != EOF_TOKEN && token != endToken);
537 return names;
538 }
539
540 bool canNamesResolveTo(
541 Map<String, List<String>> names,
542 Element element,
543 ClassElement cls) {
544 if (names.containsKey(element.name)) {
545 return true;
546 }
547 if (cls != null) {
548 List<String> rest = names[cls.name];
549 if (rest != null && rest.contains(element.name)) {
550 // [names] contains C.m, where C is the name of [cls], and m is the name
551 // of [element].
552 return true;
553 }
554 }
555 return false;
556 }
557
558 DeclarationSite declarationSite(Element element) {
559 return element is ElementX ? element.declarationSite : null;
560 }
OLDNEW
« no previous file with comments | « dart/pkg/compiler/lib/src/elements/modelx.dart ('k') | dart/tests/try/web/incremental_compilation_update_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698