Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Fletch 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.md file. | 3 // BSD-style license that can be found in the LICENSE.md file. |
| 4 | 4 |
| 5 library fletchc.dynamic_call_enqueuer; | 5 library fletchc.dynamic_call_enqueuer; |
| 6 | 6 |
| 7 import 'dart:collection' show | 7 import 'dart:collection' show |
| 8 Queue; | 8 Queue; |
| 9 | 9 |
| 10 import 'package:compiler/src/dart2jslib.dart' show | |
| 11 EnqueueTask; | |
| 12 | |
| 13 import 'package:compiler/src/universe/universe.dart' show | 10 import 'package:compiler/src/universe/universe.dart' show |
| 14 CallStructure, | 11 CallStructure, |
| 12 Selector, | |
| 15 UniverseSelector; | 13 UniverseSelector; |
| 16 | 14 |
| 17 import 'package:compiler/src/dart_types.dart' show | 15 import 'package:compiler/src/dart_types.dart' show |
| 18 InterfaceType; | 16 InterfaceType; |
| 19 | 17 |
| 20 import 'package:compiler/src/elements/elements.dart' show | 18 import 'package:compiler/src/elements/elements.dart' show |
| 21 ClassElement, | 19 ClassElement, |
| 22 Element, | 20 Element, |
| 21 FunctionElement, | |
| 23 Name; | 22 Name; |
| 24 | 23 |
| 25 import 'package:compiler/src/util/util.dart' show | 24 import 'package:compiler/src/util/util.dart' show |
| 26 Hashing; | 25 Hashing; |
| 27 | 26 |
| 28 import 'fletch_compiler_implementation.dart' show | 27 import 'fletch_compiler_implementation.dart' show |
| 29 FletchCompilerImplementation; | 28 FletchCompilerImplementation; |
| 30 | 29 |
| 30 typedef void ElementUsage(Element element, UniverseSelector selector); | |
| 31 | |
| 31 /// Implements the dynamic part of the tree-shaking algorithm. | 32 /// Implements the dynamic part of the tree-shaking algorithm. |
| 32 /// | 33 /// |
| 33 /// By "dynamic" part we mean the part that is about matching instantiated | 34 /// By "dynamic" part we mean the part that is about matching instantiated |
| 34 /// classes with called instance methods. | 35 /// classes with called instance methods. |
| 35 class DynamicCallEnqueuer { | 36 class DynamicCallEnqueuer { |
| 36 final FletchCompilerImplementation compiler; | 37 final FletchCompilerImplementation compiler; |
| 37 | 38 |
| 38 final Set<ClassElement> instantiatedClasses = new Set<ClassElement>(); | 39 final Set<ClassElement> instantiatedClasses = new Set<ClassElement>(); |
| 39 | 40 |
| 40 final Queue<ClassElement> pendingInstantiatedClasses = | 41 final Queue<ClassElement> pendingInstantiatedClasses = |
| 41 new Queue<ClassElement>(); | 42 new Queue<ClassElement>(); |
| 42 | 43 |
| 43 final Set<UntypedSelector> enqueuedSelectors = new Set<UntypedSelector>(); | 44 final Set<Selector> enqueuedSelectors = new Set<Selector>(); |
| 44 | 45 |
| 45 final Queue<UntypedSelector> pendingSelectors = | 46 final Queue<Selector> pendingSelectors = new Queue<Selector>(); |
| 46 new Queue<UntypedSelector>(); | |
| 47 | 47 |
| 48 final Set<UniverseSelector> newlySeenSelectors; | 48 final Set<UniverseSelector> newlySeenSelectors; |
| 49 | 49 |
| 50 EnqueueTask task; | |
| 51 | |
| 52 DynamicCallEnqueuer(FletchCompilerImplementation compiler) | 50 DynamicCallEnqueuer(FletchCompilerImplementation compiler) |
| 53 : compiler = compiler, | 51 : compiler = compiler, |
| 54 newlySeenSelectors = compiler.cacheStrategy.newSet(); | 52 newlySeenSelectors = compiler.cacheStrategy.newSet(); |
| 55 | 53 |
| 56 void registerInstantiatedType(InterfaceType type) { | 54 void registerInstantiatedType(InterfaceType type) { |
| 57 ClassElement cls = type.element.declaration; | 55 ClassElement cls = type.element.declaration; |
| 58 if (instantiatedClasses.add(cls)) { | 56 if (instantiatedClasses.add(cls)) { |
| 59 pendingInstantiatedClasses.addLast(cls); | 57 pendingInstantiatedClasses.addLast(cls); |
| 60 } | 58 } |
| 61 } | 59 } |
| 62 | 60 |
| 63 void enqueueApplicableMembers( | 61 void enqueueApplicableMembers( |
| 64 ClassElement cls, | 62 ClassElement cls, |
| 65 UntypedSelector selector, | 63 Selector selector, |
| 66 void enqueueElement(Element element)) { | 64 ElementUsage enqueueElement) { |
| 67 Element member = cls.lookupByName(selector.name); | 65 Element member = cls.lookupByName(selector.memberName); |
| 68 if (member != null && task.resolution.isProcessed(member)) { | 66 if (member == null) return; |
| 69 // TODO(ahe): Check if selector applies; Don't consult resolution. | 67 if (!member.isInstanceMember) return; |
| 70 enqueueElement(member); | 68 if (selector.isGetter) { |
| 69 if (member.isField || member.isGetter) { | |
| 70 enqueueElement(member, new UniverseSelector(selector, null)); | |
| 71 } else { | |
| 72 // Tear-off. | |
| 73 compiler.reportVerboseInfo( | |
| 74 member, "enqueued as tear-off", forceVerbose: true); | |
| 75 enqueueElement(member, new UniverseSelector(selector, null)); | |
| 76 } | |
| 77 } else if (selector.isSetter) { | |
| 78 if (member.isField || member.isSetter) { | |
| 79 enqueueElement(member, new UniverseSelector(selector, null)); | |
| 80 } | |
| 81 } else if (member.isFunction && selector.signatureApplies(member)) { | |
| 82 enqueueElement(member, new UniverseSelector(selector, null)); | |
| 71 } | 83 } |
| 72 } | 84 } |
| 73 | 85 |
| 74 void enqueueInstanceMethods(void enqueueElement(Element element)) { | 86 void enqueueInstanceMethods(ElementUsage enqueueElement) { |
| 75 while (!pendingInstantiatedClasses.isEmpty) { | 87 while (!pendingInstantiatedClasses.isEmpty) { |
| 76 ClassElement cls = pendingInstantiatedClasses.removeFirst(); | 88 ClassElement cls = pendingInstantiatedClasses.removeFirst(); |
| 77 compiler.reportVerboseInfo(cls, "was instantiated", forceVerbose: true); | 89 compiler.reportVerboseInfo(cls, "was instantiated", forceVerbose: true); |
| 78 for (UntypedSelector selector in enqueuedSelectors) { | 90 for (Selector selector in enqueuedSelectors) { |
| 79 // TODO(ahe): As we iterate over enqueuedSelectors, we may end up | 91 // TODO(ahe): As we iterate over enqueuedSelectors, we may end up |
| 80 // processing calling _enqueueApplicableMembers twice for newly | 92 // processing calling _enqueueApplicableMembers twice for newly |
| 81 // instantiated classes. Once here, and then once more in the while | 93 // instantiated classes. Once here, and then once more in the while |
| 82 // loop below. | 94 // loop below. |
| 83 enqueueApplicableMembers(cls, selector, enqueueElement); | 95 enqueueApplicableMembers(cls, selector, enqueueElement); |
| 84 } | 96 } |
| 85 } | 97 } |
| 86 while (!pendingSelectors.isEmpty) { | 98 while (!pendingSelectors.isEmpty) { |
| 87 UntypedSelector selector = pendingSelectors.removeFirst(); | 99 Selector selector = pendingSelectors.removeFirst(); |
| 88 compiler.reportVerboseInfo( | 100 compiler.reportVerboseInfo( |
| 89 null, "$selector was called", forceVerbose: true); | 101 null, "$selector was called", forceVerbose: true); |
| 90 for (ClassElement cls in instantiatedClasses) { | 102 for (ClassElement cls in instantiatedClasses) { |
| 91 enqueueApplicableMembers(cls, selector, enqueueElement); | 103 enqueueApplicableMembers(cls, selector, enqueueElement); |
| 92 } | 104 } |
| 93 } | 105 } |
| 94 } | 106 } |
| 95 | 107 |
| 96 void enqueueSelector(UniverseSelector universeSelector) { | 108 void enqueueSelector(UniverseSelector universeSelector) { |
| 97 UntypedSelector selector = | 109 assert(universeSelector.mask == null); |
| 98 new UntypedSelector.fromUniverseSelector(universeSelector); | 110 Selector selector = universeSelector.selector; |
| 99 if (enqueuedSelectors.add(selector)) { | 111 if (enqueuedSelectors.add(selector)) { |
| 100 pendingSelectors.add(selector); | 112 pendingSelectors.add(selector); |
| 101 newlySeenSelectors.add(universeSelector); | 113 newlySeenSelectors.add(universeSelector); |
| 102 } | 114 } |
| 103 } | 115 } |
| 104 | 116 |
| 105 void forgetElement(Element element) { | 117 void forgetElement(Element element) { |
| 106 // TODO(ahe): Make sure that the incremental compiler | 118 // TODO(ahe): Make sure that the incremental compiler |
| 107 // (library_updater.dart) registers classes with schema changes as having | 119 // (library_updater.dart) registers classes with schema changes as having |
| 108 // been instantiated. | 120 // been instantiated. |
| 109 instantiatedClasses.remove(element); | 121 instantiatedClasses.remove(element); |
| 110 } | 122 } |
| 111 } | 123 } |
| 112 | |
| 113 /// Represents information about a call site. | |
| 114 /// | |
| 115 /// This class differ from [UniverseSelector] in two key areas: | |
| 116 /// | |
| 117 /// 1. Implements `operator ==` (and is thus suitable for use in a [Set]) | |
|
ahe
2015/09/03 15:07:10
I had overlooked that Selector is canonicalized an
Johnni Winther
2015/09/03 16:21:17
They might actually not always be canonicalized bu
ahe
2015/09/03 16:24:09
That's good enough for me :-)
| |
| 118 /// 2. Has no type mask | |
| 119 class UntypedSelector { | |
| 120 final Name name; | |
| 121 | |
| 122 final bool isGetter; | |
| 123 | |
| 124 final bool isSetter; | |
| 125 | |
| 126 final CallStructure structure; | |
| 127 | |
| 128 final int hashCode; | |
| 129 | |
| 130 UntypedSelector( | |
| 131 this.name, | |
| 132 this.isGetter, | |
| 133 this.isSetter, | |
| 134 this.structure, | |
| 135 this.hashCode); | |
| 136 | |
| 137 factory UntypedSelector.fromUniverseSelector(UniverseSelector selector) { | |
| 138 if (selector.mask != null) { | |
| 139 throw new ArgumentError("[selector] has non-null type mask"); | |
| 140 } | |
| 141 Name name = selector.selector.memberName; | |
| 142 CallStructure structure = selector.selector.callStructure; | |
| 143 bool isGetter = selector.selector.isGetter; | |
| 144 bool isSetter = selector.selector.isSetter; | |
| 145 int hash = Hashing.mixHashCodeBits(name.hashCode, structure.hashCode); | |
| 146 hash = Hashing.mixHashCodeBits(hash, isSetter.hashCode); | |
| 147 hash = Hashing.mixHashCodeBits(hash, isGetter.hashCode); | |
| 148 return new UntypedSelector(name, isGetter, isSetter, structure, hash); | |
| 149 } | |
| 150 | |
| 151 bool operator ==(other) { | |
| 152 if (other is UntypedSelector) { | |
| 153 return name == other.name && | |
| 154 isGetter == other.isGetter && isSetter == other.isSetter && | |
| 155 structure == other.structure; | |
| 156 } else { | |
| 157 return false; | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 String toString() { | |
| 162 return | |
| 163 'UntypedSelector($name, ' | |
| 164 '${isGetter ? "getter, " : ""}' | |
| 165 '${isSetter ? "setter, " : ""}' | |
| 166 '$structure)'; | |
| 167 } | |
| 168 } | |
| OLD | NEW |