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 |