Chromium Code Reviews| 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 |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 228 if (element is PartialFunctionElement) { | 228 if (element is PartialFunctionElement) { |
| 229 return canReuseRemovedFunction(element); | 229 return canReuseRemovedFunction(element); |
| 230 } | 230 } |
| 231 return cannotReuse( | 231 return cannotReuse( |
| 232 element, "Removed element that isn't a method."); | 232 element, "Removed element that isn't a method."); |
| 233 } | 233 } |
| 234 | 234 |
| 235 bool canReuseRemovedFunction(PartialFunctionElement element) { | 235 bool canReuseRemovedFunction(PartialFunctionElement element) { |
| 236 logVerbose("Removed method $element."); | 236 logVerbose("Removed method $element."); |
| 237 | 237 |
| 238 PartialClassElement cls = element.enclosingClass; | 238 ScopeContainerElement container = element.enclosingElement; |
| 239 for (ScopeContainerElement scope in scopesAffectedBy(element, cls)) { | 239 for (ScopeContainerElement scope in scopesAffectedBy(element, container)) { |
| 240 scanSites(scope, (Element member, DeclarationSite site) { | 240 scanSites(scope, (Element member, DeclarationSite site) { |
| 241 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior. | 241 // TODO(ahe): Cache qualifiedNamesIn to avoid quadratic behavior. |
| 242 Map<String, List<String>> names = qualifiedNamesIn(site); | 242 Map<String, List<String>> names = qualifiedNamesIn(site); |
| 243 if (canNamesResolveTo(names, element, cls)) { | 243 if (canNamesResolveTo(names, element, container)) { |
| 244 _elementsToInvalidate.add(member); | 244 _elementsToInvalidate.add(member); |
| 245 } | 245 } |
| 246 }); | 246 }); |
| 247 } | 247 } |
| 248 | 248 |
| 249 _removedElements.add(element); | 249 _removedElements.add(element); |
| 250 | 250 |
| 251 updates.add(new RemovedFunctionUpdate(compiler, element)); | 251 updates.add(new RemovedFunctionUpdate(compiler, element)); |
| 252 | 252 |
| 253 return true; | 253 return true; |
| 254 } | 254 } |
| 255 | 255 |
| 256 /// Invoke [f] on each [DeclarationSite] in [element]. If [element] is a | |
| 257 /// [ScopeContainerElement], invoke f on all local members as well. | |
| 256 void scanSites( | 258 void scanSites( |
| 257 Element element, | 259 Element element, |
| 258 void f(ElementX element, DeclarationSite site)) { | 260 void f(ElementX element, DeclarationSite site)) { |
| 259 DeclarationSite site = declarationSite(element); | 261 DeclarationSite site = declarationSite(element); |
| 260 if (site != null) { | 262 if (site != null) { |
| 261 f(element, site); | 263 f(element, site); |
| 262 } | 264 } |
| 263 if (element is ScopeContainerElement) { | 265 if (element is ScopeContainerElement) { |
| 264 element.forEachLocalMember((member) { scanSites(member, f); }); | 266 element.forEachLocalMember((member) { scanSites(member, f); }); |
| 265 } | 267 } |
| 266 } | 268 } |
| 267 | 269 |
| 270 /// Assume [element] is either removed from or added to [container], and | |
| 271 /// return all [ScopeContainerElement] that can see this change. | |
| 268 List<ScopeContainerElement> scopesAffectedBy( | 272 List<ScopeContainerElement> scopesAffectedBy( |
| 269 Element element, | 273 Element element, |
| 270 ClassElement cls) { | 274 ScopeContainerElement container) { |
| 271 // TODO(ahe): Use library export graph to compute this. | 275 // TODO(ahe): Use library export graph to compute this. |
| 272 // TODO(ahe): Should return all user-defined libraries and packages. | 276 // TODO(ahe): Should return all user-defined libraries and packages. |
| 273 LibraryElement library = element.library; | 277 LibraryElement library = container.library; |
| 274 List<ScopeContainerElement> result = <ScopeContainerElement>[library]; | 278 List<ScopeContainerElement> result = <ScopeContainerElement>[library]; |
| 275 | 279 |
| 276 if (cls == null) return result; | 280 if (!container.isClass) return result; |
| 281 | |
| 282 ClassElement cls = container; | |
| 277 | 283 |
| 278 var externalSubtypes = | 284 var externalSubtypes = |
| 279 compiler.world.subtypesOf(cls).where((e) => e.library != library); | 285 compiler.world.subtypesOf(cls).where((e) => e.library != library); |
| 280 | 286 |
| 281 return result..addAll(externalSubtypes); | 287 return result..addAll(externalSubtypes); |
| 282 } | 288 } |
| 283 | 289 |
| 284 /// Returns true if function [before] can be reused to reflect the changes in | 290 /// Returns true if function [before] can be reused to reflect the changes in |
| 285 /// [after]. | 291 /// [after]. |
| 286 /// | 292 /// |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 667 if (superName != null) { | 673 if (superName != null) { |
| 668 updates.add( | 674 updates.add( |
| 669 js.statement('delete #.prototype.#', [elementAccess, superName])); | 675 js.statement('delete #.prototype.#', [elementAccess, superName])); |
| 670 } | 676 } |
| 671 } else { | 677 } else { |
| 672 updates.add(js.statement('delete #', [elementAccess])); | 678 updates.add(js.statement('delete #', [elementAccess])); |
| 673 } | 679 } |
| 674 } | 680 } |
| 675 } | 681 } |
| 676 | 682 |
| 677 Map<String, List<String>> qualifiedNamesIn(PartialElement element) { | 683 /// Returns all qualified names in [element] with less than four identifiers. A |
| 684 /// qualified name is an identifier followed by a sequence of dots and | |
| 685 /// identifiers, for example, "x", and "x.y.z". But not "x.y.z.w" ("w" is the | |
| 686 /// fourth identifier). | |
|
Johnni Winther
2014/11/14 10:33:35
I guess the reason for the limit is prefix.Class.s
ahe
2014/11/17 10:39:47
Done.
| |
| 687 Set<String> qualifiedNamesIn(PartialElement element) { | |
| 678 Token beginToken = element.beginToken; | 688 Token beginToken = element.beginToken; |
| 679 Token endToken = element.endToken; | 689 Token endToken = element.endToken; |
| 680 Token token = beginToken; | 690 Token token = beginToken; |
| 681 if (element is PartialClassElement) { | 691 if (element is PartialClassElement) { |
| 682 ClassNode node = element.cachedNode; | 692 ClassNode node = element.cachedNode; |
| 683 if (node != null) { | 693 if (node != null) { |
| 684 NodeList body = node.body; | 694 NodeList body = node.body; |
| 685 if (body != null) { | 695 if (body != null) { |
| 686 endToken = body.beginToken; | 696 endToken = body.beginToken; |
| 687 } | 697 } |
| 688 } | 698 } |
| 689 } | 699 } |
| 690 Map<String, List<String>> names = new Map<String, List<String>>(); | 700 Set<String> names = new Set<String>(); |
| 691 List<List<Token>> qualifieds = <List<Token>>[]; | |
| 692 do { | 701 do { |
| 693 if (token.isIdentifier()) { | 702 if (token.isIdentifier()) { |
| 694 List<String> name = names.putIfAbsent(token.value, () => <String>[]); | 703 String name = token.value; |
| 695 while (identical('.', token.next.stringValue) && | 704 // [name] is a single "identifier". |
| 696 token.next.next.isIdentifier()) { | 705 names.add(name); |
| 706 if (identical('.', token.next.stringValue) && | |
| 707 token.next.next.isIdentifier()) { | |
| 697 token = token.next.next; | 708 token = token.next.next; |
| 698 name.add(token.value); | 709 name += '.${token.value}'; |
| 710 // [name] is "idenfifier.idenfifier". | |
| 711 names.add(name); | |
| 712 | |
| 713 if (identical('.', token.next.stringValue) && | |
| 714 token.next.next.isIdentifier()) { | |
| 715 token = token.next.next; | |
| 716 name += '.${token.value}'; | |
| 717 // [name] is "idenfifier.idenfifier.idenfifier". | |
| 718 names.add(name); | |
| 719 | |
| 720 while (identical('.', token.next.stringValue) && | |
| 721 token.next.next.isIdentifier()) { | |
| 722 // Skip remaining identifiers, they cannot statically resolve to | |
| 723 // anything, and must be dynamic sends. | |
| 724 token = token.next.next; | |
| 725 } | |
| 726 } | |
| 699 } | 727 } |
| 700 } | 728 } |
| 701 token = token.next; | 729 token = token.next; |
| 702 } while (token.kind != EOF_TOKEN && token != endToken); | 730 } while (token.kind != EOF_TOKEN && token != endToken); |
| 703 return names; | 731 return names; |
| 704 } | 732 } |
| 705 | 733 |
| 734 /// Returns true if one of the qualified names in names (as computed by | |
| 735 /// [qualifiedNamesIn]) could be a static reference to [element]. | |
| 706 bool canNamesResolveTo( | 736 bool canNamesResolveTo( |
|
Johnni Winther
2014/11/14 10:33:35
Maybe rename to 'canNamesResolveStaticallyTo'
ahe
2014/11/17 10:39:47
Done.
| |
| 707 Map<String, List<String>> names, | 737 Set<String> names, |
| 708 Element element, | 738 Element element, |
| 709 ClassElement cls) { | 739 ScopeContainerElement container) { |
| 710 if (names.containsKey(element.name)) { | 740 if (names.contains(element.name)) return true; |
| 711 return true; | 741 if (container != null && container.isClass) { |
| 742 // [names] contains C.m, where C is the name of [container], and m is the | |
| 743 // name of [element]. | |
| 744 if (names.contains("${container.name}.${element.name}")) return true; | |
| 712 } | 745 } |
| 713 if (cls != null) { | 746 // TODO(ahe): Check for prefixes as well. |
| 714 List<String> rest = names[cls.name]; | |
| 715 if (rest != null && rest.contains(element.name)) { | |
| 716 // [names] contains C.m, where C is the name of [cls], and m is the name | |
| 717 // of [element]. | |
| 718 return true; | |
| 719 } | |
| 720 } | |
| 721 return false; | 747 return false; |
| 722 } | 748 } |
| 723 | 749 |
| 724 DeclarationSite declarationSite(Element element) { | 750 DeclarationSite declarationSite(Element element) { |
| 725 return element is ElementX ? element.declarationSite : null; | 751 return element is ElementX ? element.declarationSite : null; |
| 726 } | 752 } |
| 727 | 753 |
| 728 abstract class JsFeatures { | 754 abstract class JsFeatures { |
| 729 Compiler get compiler; | 755 Compiler get compiler; |
| 730 | 756 |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 742 | 768 |
| 743 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; | 769 ClassEmitter get classEmitter => backend.emitter.oldEmitter.classEmitter; |
| 744 | 770 |
| 745 List<String> computeFields(ClassElement cls) { | 771 List<String> computeFields(ClassElement cls) { |
| 746 // TODO(ahe): Rewrite for new emitter. | 772 // TODO(ahe): Rewrite for new emitter. |
| 747 ClassBuilder builder = new ClassBuilder(cls, namer); | 773 ClassBuilder builder = new ClassBuilder(cls, namer); |
| 748 classEmitter.emitFields(cls, builder, ""); | 774 classEmitter.emitFields(cls, builder, ""); |
| 749 return builder.fields; | 775 return builder.fields; |
| 750 } | 776 } |
| 751 } | 777 } |
| OLD | NEW |