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

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

Issue 714843002: Delete instance methods. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: 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
« no previous file with comments | « no previous file | dart/tests/try/web/incremental_compilation_update_test.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) 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
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 FailedUpdate(this.context, this.message); 80 FailedUpdate(this.context, this.message);
81 81
82 String toString() { 82 String toString() {
83 if (context == null) return '$message'; 83 if (context == null) return '$message';
84 return 'In $context:\n $message'; 84 return 'In $context:\n $message';
85 } 85 }
86 } 86 }
87 87
88 // TODO(ahe): Generalize this class. For now only works for Compiler.mainApp, 88 // TODO(ahe): Generalize this class. For now only works for Compiler.mainApp,
89 // and only if that library has exactly one compilation unit. 89 // and only if that library has exactly one compilation unit.
90 class LibraryUpdater { 90 class LibraryUpdater extends JsFeatures {
91 final Compiler compiler; 91 final Compiler compiler;
92 92
93 final api.CompilerInputProvider inputProvider; 93 final api.CompilerInputProvider inputProvider;
94 94
95 final Logger logTime; 95 final Logger logTime;
96 96
97 final Logger logVerbose; 97 final Logger logVerbose;
98 98
99 // 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
100 // changed. 100 // changed.
101 final Uri uri; 101 final Uri uri;
102 102
103 final List<Update> updates = <Update>[]; 103 final List<Update> updates = <Update>[];
104 104
105 final List<FailedUpdate> _failedUpdates = <FailedUpdate>[]; 105 final List<FailedUpdate> _failedUpdates = <FailedUpdate>[];
106 106
107 final Set<ElementX> _elementsToInvalidate = new Set<ElementX>(); 107 final Set<ElementX> _elementsToInvalidate = new Set<ElementX>();
108 108
109 final Set<ElementX> _removedElements = new Set<ElementX>();
110
109 LibraryUpdater( 111 LibraryUpdater(
110 this.compiler, 112 this.compiler,
111 this.inputProvider, 113 this.inputProvider,
112 this.uri, 114 this.uri,
113 this.logTime, 115 this.logTime,
114 this.logVerbose); 116 this.logVerbose);
115 117
116 /// When [true], updates must be applied (using [applyUpdates]) before the 118 /// When [true], updates must be applied (using [applyUpdates]) before the
117 /// [compiler]'s state correctly reflects the updated program. 119 /// [compiler]'s state correctly reflects the updated program.
118 bool get hasPendingUpdates => !updates.isEmpty; 120 bool get hasPendingUpdates => !updates.isEmpty;
119 121
120 bool get failed => !_failedUpdates.isEmpty; 122 bool get failed => !_failedUpdates.isEmpty;
121 123
122 JavaScriptBackend get backend => compiler.backend;
123
124 Namer get namer => backend.namer;
125
126 CodeEmitterTask get emitter => backend.emitter;
127
128 /// Used as tear-off passed to [LibraryLoaderTask.resetAsync]. 124 /// Used as tear-off passed to [LibraryLoaderTask.resetAsync].
129 Future<bool> reuseLibrary(LibraryElement library) { 125 Future<bool> reuseLibrary(LibraryElement library) {
130 assert(compiler != null); 126 assert(compiler != null);
131 if (library.isPlatformLibrary || library.isPackageLibrary) { 127 if (library.isPlatformLibrary || library.isPackageLibrary) {
132 logTime('Reusing $library.'); 128 logTime('Reusing $library.');
133 return new Future.value(true); 129 return new Future.value(true);
134 } else if (library != compiler.mainApp) { 130 } else if (library != compiler.mainApp) {
135 return new Future.value(false); 131 return new Future.value(false);
136 } 132 }
137 return inputProvider(uri).then((bytes) { 133 return inputProvider(uri).then((bytes) {
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 for (ScopeContainerElement scope in scopesAffectedBy(element, cls)) { 239 for (ScopeContainerElement scope in scopesAffectedBy(element, cls)) {
244 scanSites(scope, (Element member, DeclarationSite site) { 240 scanSites(scope, (Element member, DeclarationSite site) {
245 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior. 241 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior.
246 Map<String, List<String>> names = qualifiedNamesIn(site); 242 Map<String, List<String>> names = qualifiedNamesIn(site);
247 if (canNamesResolveTo(names, element, cls)) { 243 if (canNamesResolveTo(names, element, cls)) {
248 _elementsToInvalidate.add(member); 244 _elementsToInvalidate.add(member);
249 } 245 }
250 }); 246 });
251 } 247 }
252 248
253 // TODO(ahe): Don't modify the class here, instead use an instance of 249 _removedElements.add(element);
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 250
265 // TODO(ahe): Also compute a patch which removes the function, e.g., 251 updates.add(new RemovedFunctionUpdate(compiler, element));
266 // "delete GlobalObject.MyClass.prototype.memberName".
267
268 // TODO(ahe): Also forget [element].
269 252
270 return true; 253 return true;
271 } 254 }
272 255
273 void scanSites( 256 void scanSites(
274 Element element, 257 Element element,
275 void f(ElementX element, DeclarationSite site)) { 258 void f(ElementX element, DeclarationSite site)) {
276 DeclarationSite site = declarationSite(element); 259 DeclarationSite site = declarationSite(element);
277 if (site != null) { 260 if (site != null) {
278 f(element, site); 261 f(element, site);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
356 bool unableToReuse( 339 bool unableToReuse(
357 Token diffToken, 340 Token diffToken,
358 PartialElement before, 341 PartialElement before,
359 PartialElement after) { 342 PartialElement after) {
360 return cannotReuse( 343 return cannotReuse(
361 after, 344 after,
362 'Unhandled change:' 345 'Unhandled change:'
363 ' ${before} (${before.runtimeType} -> ${after.runtimeType}).'); 346 ' ${before} (${before.runtimeType} -> ${after.runtimeType}).');
364 } 347 }
365 348
366 List<Element> applyUpdates() { 349 List<Element> applyUpdates([List<Update> removals]) {
Johnni Winther 2014/11/14 08:55:26 Document this, especially semantics of the return
ahe 2014/11/14 14:33:12 Will do in a follow-up.
350 for (Update update in updates) {
351 update.captureState();
352 }
367 if (!_failedUpdates.isEmpty) { 353 if (!_failedUpdates.isEmpty) {
368 throw new StateError( 354 throw new StateError(
369 "Can't compute update.\n\n${_failedUpdates.join('\n\n')}"); 355 "Can't compute update.\n\n${_failedUpdates.join('\n\n')}");
370 } 356 }
371 for (ElementX element in _elementsToInvalidate) { 357 for (ElementX element in _elementsToInvalidate) {
372 compiler.forgetElement(element); 358 compiler.forgetElement(element);
373 element.reuseElement(); 359 element.reuseElement();
374 } 360 }
375 return updates.map((Update update) => update.apply()).toList() 361 List<Element> elementsToInvalidate = <Element>[];
376 ..addAll(_elementsToInvalidate); 362 for (ElementX element in _elementsToInvalidate) {
363 if (!_removedElements.contains(element)) {
364 elementsToInvalidate.add(element);
365 }
366 }
367 for (Update update in updates) {
368 Element element = update.apply();
369 if (update.isRemoval) {
370 if (removals != null) {
371 removals.add(update);
372 }
373 } else {
374 elementsToInvalidate.add(element);
375 }
376 }
377 return elementsToInvalidate;
377 } 378 }
378 379
379 String computeUpdateJs() { 380 String computeUpdateJs() {
380 List<Element> updatedElements = applyUpdates(); 381 List<Update> removals = <Update>[];
382 List<Element> updatedElements = applyUpdates(removals);
381 if (compiler.progress != null) { 383 if (compiler.progress != null) {
382 compiler.progress.reset(); 384 compiler.progress.reset();
383 } 385 }
384 for (Element element in updatedElements) { 386 for (Element element in updatedElements) {
385 compiler.enqueuer.resolution.addToWorkList(element); 387 compiler.enqueuer.resolution.addToWorkList(element);
386 } 388 }
387 compiler.processQueue(compiler.enqueuer.resolution, null); 389 compiler.processQueue(compiler.enqueuer.resolution, null);
388 390
389 compiler.phase = Compiler.PHASE_DONE_RESOLVING; 391 compiler.phase = Compiler.PHASE_DONE_RESOLVING;
390 392
391 for (Element element in updatedElements) { 393 for (Element element in updatedElements) {
392 compiler.enqueuer.codegen.addToWorkList(element); 394 compiler.enqueuer.codegen.addToWorkList(element);
393 } 395 }
394 compiler.processQueue(compiler.enqueuer.codegen, null); 396 compiler.processQueue(compiler.enqueuer.codegen, null);
395 397
396 List<jsAst.Statement> updates = <jsAst.Statement>[]; 398 List<jsAst.Statement> updates = <jsAst.Statement>[];
397 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) { 399 for (Element element in compiler.enqueuer.codegen.newlyEnqueuedElements) {
398 if (!element.isField) { 400 if (!element.isField) {
399 updates.add(computeMemberUpdateJs(element)); 401 updates.add(computeMemberUpdateJs(element));
400 } 402 }
401 } 403 }
404 for (RemovedFunctionUpdate update in removals) {
405 update.writeUpdateJsOn(updates);
406 }
402 407
403 if (updates.length == 1) { 408 if (updates.length == 1) {
404 return prettyPrintJs(updates.single); 409 return prettyPrintJs(updates.single);
405 } else { 410 } else {
406 return prettyPrintJs(js.statement('{#}', [updates])); 411 return prettyPrintJs(js.statement('{#}', [updates]));
407 } 412 }
408 } 413 }
409 414
410 jsAst.Node computeMemberUpdateJs(Element element) { 415 jsAst.Node computeMemberUpdateJs(Element element) {
411 MemberInfo info = emitter.oldEmitter.containerBuilder 416 MemberInfo info = emitter.oldEmitter.containerBuilder
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
469 final Compiler compiler; 474 final Compiler compiler;
470 475
471 PartialElement get before; 476 PartialElement get before;
472 477
473 PartialElement get after; 478 PartialElement get after;
474 479
475 Update(this.compiler); 480 Update(this.compiler);
476 481
477 /// Applies the update to [before] and returns that element. 482 /// Applies the update to [before] and returns that element.
478 PartialElement apply(); 483 PartialElement apply();
484
485 bool get isRemoval => false;
486
487 /// Called before any patches are applied to capture any state that is needed
488 /// later.
489 void captureState() {
490 }
479 } 491 }
480 492
481 /// Represents an update of a function element. 493 /// Represents an update of a function element.
482 class FunctionUpdate extends Update { 494 class FunctionUpdate extends Update with ReuseFunction {
483 final PartialFunctionElement before; 495 final PartialFunctionElement before;
484 496
485 final PartialFunctionElement after; 497 final PartialFunctionElement after;
486 498
487 FunctionUpdate(Compiler compiler, this.before, this.after) 499 FunctionUpdate(Compiler compiler, this.before, this.after)
488 : super(compiler); 500 : super(compiler);
489 501
490 PartialFunctionElement apply() { 502 PartialFunctionElement apply() {
491 patchElement(); 503 patchElement();
492 reuseElement(); 504 reuseElement();
493 return before; 505 return before;
494 } 506 }
495 507
496 /// Destructively change the tokens in [before] to match those of [after]. 508 /// Destructively change the tokens in [before] to match those of [after].
497 void patchElement() { 509 void patchElement() {
498 before.beginToken = after.beginToken; 510 before.beginToken = after.beginToken;
499 before.endToken = after.endToken; 511 before.endToken = after.endToken;
500 before.getOrSet = after.getOrSet; 512 before.getOrSet = after.getOrSet;
501 } 513 }
514 }
515
516 abstract class ReuseFunction {
517 PartialFunctionElement get before;
502 518
503 /// Reset various caches and remove this element from the compiler's internal 519 /// Reset various caches and remove this element from the compiler's internal
504 /// state. 520 /// state.
505 void reuseElement() { 521 void reuseElement() {
506 compiler.forgetElement(before); 522 compiler.forgetElement(before);
507 before.reuseElement(); 523 before.reuseElement();
508 } 524 }
509 } 525 }
510 526
527 class RemovedFunctionUpdate extends Update with JsFeatures, ReuseFunction {
528 final PartialFunctionElement element;
529
530 /// Name of property to remove using JavaScript "delete".
531 String name;
532
533 /// Name of super-alias property to remove using JavaScript "delete". Null
534 /// for methods that aren't "super aliased" (should imply that this field is
535 /// null for all non-instance methods).
536 String superName;
537
538 bool wasStateCaptured = false;
539
540 RemovedFunctionUpdate(Compiler compiler, this.element)
541 : super(compiler);
542
543 PartialFunctionElement get before => element;
544
545 PartialElement get after => null;
546
547 bool get isRemoval => true;
548
549 void captureState() {
550 if (wasStateCaptured) throw "captureState was called twice.";
551
552 if (element.isInstanceMember) {
553 name = namer.getNameOfMember(element);
554 }
555 if (backend.isAliasedSuperMember(element)) {
556 superName = namer.getNameOfAliasedSuperMember(element);
557 }
558
559 wasStateCaptured = true;
560 }
561
562 PartialElement apply() {
563 if (!wasStateCaptured) throw "captureState must be called before apply.";
564 removeFromEnclosingClass();
565 reuseElement();
566 return null;
567 }
568
569 void removeFromEnclosingClass() {
570 PartialClassElement cls = element.enclosingClass;
571
572 Link<Element> localMembersReversed = const Link<Element>();
573 bool foundElement = false;
574 cls.forEachLocalMember((member) {
575 if (member != element) {
576 localMembersReversed = localMembersReversed.prepend(member);
577 } else {
578 if (foundElement) {
579 throw "Found '$element' twice in '$cls'.";
580 }
581 foundElement = true;
582 }
583 });
584 if (!foundElement) {
585 throw "Don't find '$element' in '$cls'.";
586 }
587 cls.localMembersCache = null;
588 cls.localMembersReversed = localMembersReversed;
589 cls.localScope.contents.remove(element.name);
590
591 return null;
592 }
593
594 void writeUpdateJsOn(List<jsAst.Statement> updates) {
595 if (name == null) {
596 compiler.internalError(element, '${element.runtimeType}');
597 }
598 if (element.isInstanceMember) {
599 jsAst.Node elementAccess = namer.elementAccess(element.enclosingClass);
600 updates.add(
601 js.statement('delete #.prototype.#', [elementAccess, name]));
602
603 if (superName != null) {
604 updates.add(
605 js.statement('delete #.prototype.#', [elementAccess, superName]));
606 }
607 } else {
608 compiler.internalError(
609 element, 'Removal of non-instance methods not yest supported.');
Johnni Winther 2014/11/14 08:55:26 non-instance -> static
ahe 2014/11/14 14:33:12 You missed the misspelling of "yet" ;-) Regardles
610 }
611 }
612 }
613
511 Map<String, List<String>> qualifiedNamesIn(PartialElement element) { 614 Map<String, List<String>> qualifiedNamesIn(PartialElement element) {
512 Token beginToken = element.beginToken; 615 Token beginToken = element.beginToken;
513 Token endToken = element.endToken; 616 Token endToken = element.endToken;
514 Token token = beginToken; 617 Token token = beginToken;
515 if (element is PartialClassElement) { 618 if (element is PartialClassElement) {
516 ClassNode node = element.cachedNode; 619 ClassNode node = element.cachedNode;
517 if (node != null) { 620 if (node != null) {
518 NodeList body = node.body; 621 NodeList body = node.body;
519 if (body != null) { 622 if (body != null) {
520 endToken = body.beginToken; 623 endToken = body.beginToken;
(...skipping 30 matching lines...) Expand all
551 // of [element]. 654 // of [element].
552 return true; 655 return true;
553 } 656 }
554 } 657 }
555 return false; 658 return false;
556 } 659 }
557 660
558 DeclarationSite declarationSite(Element element) { 661 DeclarationSite declarationSite(Element element) {
559 return element is ElementX ? element.declarationSite : null; 662 return element is ElementX ? element.declarationSite : null;
560 } 663 }
664
665 abstract class JsFeatures {
666 Compiler get compiler;
667
668 JavaScriptBackend get backend => compiler.backend;
669
670 Namer get namer => backend.namer;
671
672 CodeEmitterTask get emitter => backend.emitter;
673 }
OLDNEW
« no previous file with comments | « no previous file | dart/tests/try/web/incremental_compilation_update_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698