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

Side by Side Diff: pkg/fletchc/lib/src/dynamic_call_enqueuer.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 10 months 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
« no previous file with comments | « pkg/fletchc/lib/src/diagnostic.dart ('k') | pkg/fletchc/lib/src/enqueuer_mixin.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file
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.
4
5 library fletchc.dynamic_call_enqueuer;
6
7 import 'dart:collection' show
8 Queue;
9
10 import 'package:compiler/src/universe/selector.dart' show
11 Selector;
12
13 import 'package:compiler/src/universe/use.dart' show
14 DynamicUse;
15
16 import 'package:compiler/src/dart_types.dart' show
17 DartType,
18 InterfaceType,
19 TypeKind;
20
21 import 'package:compiler/src/elements/elements.dart' show
22 ClassElement,
23 Element,
24 FunctionElement,
25 LibraryElement,
26 MemberElement,
27 Name;
28
29 import 'package:compiler/src/common/names.dart' show
30 Identifiers,
31 Names;
32
33 import 'package:compiler/src/util/util.dart' show
34 Hashing;
35
36 import 'fletch_compiler_implementation.dart' show
37 FletchCompilerImplementation;
38
39 import 'fletch_enqueuer.dart' show
40 shouldReportEnqueuingOfElement;
41
42 import 'fletch_registry.dart' show
43 ClosureKind;
44
45 abstract class UsageRecorder {
46 void recordElementUsage(Element element, Selector selector);
47
48 void recordClosurizationUsage(Closurization closurization, Selector selector);
49
50 void recordTypeTest(ClassElement element, InterfaceType type);
51 }
52
53 /// Implements the dynamic part of the tree-shaking algorithm.
54 ///
55 /// By "dynamic" part we mean the part that is about matching instantiated
56 /// classes with called instance methods.
57 class DynamicCallEnqueuer {
58 final FletchCompilerImplementation compiler;
59
60 final Set<ClassElement> instantiatedClasses = new Set<ClassElement>();
61
62 final Queue<ClassElement> pendingInstantiatedClasses =
63 new Queue<ClassElement>();
64
65 final Set<Selector> enqueuedSelectors = new Set<Selector>();
66
67 final Queue<Selector> pendingSelectors = new Queue<Selector>();
68
69 /// Set of functions that have been closurized
70 final Set<Closurization> implicitClosurizations = new Set<Closurization>();
71
72 /// Queue of functions that have been closurized and have yet to be
73 /// processed
74 final Queue<Closurization> pendingImplicitClosurizations =
75 new Queue<Closurization>();
76
77 final Set<InterfaceType> typeTests = new Set<InterfaceType>();
78
79 final Queue<InterfaceType> pendingTypeTests = new Queue<InterfaceType>();
80
81 DynamicCallEnqueuer(this.compiler);
82
83 void registerInstantiatedType(InterfaceType type) {
84 ClassElement cls = type.element.declaration;
85 if (instantiatedClasses.add(cls)) {
86 pendingInstantiatedClasses.addLast(cls);
87 }
88 }
89
90 void enqueueApplicableMembers(
91 ClassElement cls,
92 Selector selector,
93 UsageRecorder recorder) {
94 Element member = cls.lookupByName(selector.memberName);
95 if (member == null) return;
96 if (!member.isInstanceMember) return;
97 if (selector.isGetter) {
98 if (member.isField || member.isGetter) {
99 recorder.recordElementUsage(member, selector);
100 } else {
101 // Tear-off.
102 compiler.reportVerboseInfo(member, "enqueued as tear-off");
103 // This lets the backend generate the tear-off getter because it is
104 // told that [member] is used as a getter.
105 recorder.recordElementUsage(member, selector);
106 // This registers [member] as an instantiated closure class.
107 enqueueClosure(member, ClosureKind.tearOff);
108 }
109 } else if (selector.isSetter) {
110 if (member.isField || member.isSetter) {
111 recorder.recordElementUsage(member, selector);
112 }
113 } else if (member.isFunction && selector.signatureApplies(member)) {
114 recorder.recordElementUsage(member, selector);
115 } else if (member.isGetter || member.isField) {
116 // A getter/field can be invoked as a method, for example, if the getter
117 // returns a closure.
118 recorder.recordElementUsage(member, selector);
119 }
120 }
121
122 void enqueueClosureIfApplicable(
123 Closurization closurization,
124 Selector selector,
125 UsageRecorder recorder) {
126 FunctionElement function = closurization.function;
127 if ((selector.isGetter || selector.isCall) &&
128 selector.memberName == Names.call &&
129 selector.signatureApplies(function)) {
130 recorder.recordClosurizationUsage(closurization, selector);
131 }
132 }
133
134 void enqueueApplicableTypeTests(
135 ClassElement cls,
136 InterfaceType type,
137 UsageRecorder recorder) {
138 if (cls == type.element) {
139 recorder.recordTypeTest(cls, type);
140 return;
141 }
142 for (DartType supertype in cls.allSupertypes) {
143 if (supertype.element == type.element) {
144 recorder.recordTypeTest(cls, type);
145 return;
146 }
147 }
148 }
149
150 void enqueueInstanceMethods(UsageRecorder recorder) {
151 // TODO(ahe): Implement a faster way to iterate through selectors. For
152 // example, use the same approach as dart2js uses where selectors are
153 // grouped by name. This applies both to enqueuedSelectors and
154 // pendingSelectors.
155 while (pendingInstantiatedClasses.isNotEmpty) {
156 ClassElement cls = pendingInstantiatedClasses.removeFirst();
157 if (shouldReportEnqueuingOfElement(compiler, cls)) {
158 compiler.reportVerboseInfo(cls, "was instantiated");
159 }
160 for (Selector selector in enqueuedSelectors) {
161 // TODO(ahe): As we iterate over enqueuedSelectors, we may end up
162 // processing calling _enqueueApplicableMembers twice for newly
163 // instantiated classes. Once here, and then once more in the while
164 // loop below.
165 enqueueApplicableMembers(cls, selector, recorder);
166 }
167 for (InterfaceType type in typeTests) {
168 enqueueApplicableTypeTests(cls, type, recorder);
169 }
170 }
171 while (pendingImplicitClosurizations.isNotEmpty) {
172 Closurization closurization = pendingImplicitClosurizations.removeFirst();
173 if (shouldReportEnqueuingOfElement(compiler, closurization.function)) {
174 compiler.reportVerboseInfo(closurization.function, "was closurized");
175 }
176 for (Selector selector in enqueuedSelectors) {
177 enqueueClosureIfApplicable(closurization, selector, recorder);
178 }
179 // TODO(ahe): Also enqueue type tests here.
180 }
181 while (pendingSelectors.isNotEmpty) {
182 Selector selector = pendingSelectors.removeFirst();
183 for (ClassElement cls in instantiatedClasses) {
184 enqueueApplicableMembers(cls, selector, recorder);
185 }
186 for (Closurization closurization in implicitClosurizations) {
187 enqueueClosureIfApplicable(closurization, selector, recorder);
188 }
189 }
190 while(!pendingTypeTests.isEmpty) {
191 InterfaceType type = pendingTypeTests.removeFirst();
192 for (ClassElement cls in instantiatedClasses) {
193 enqueueApplicableTypeTests(cls, type, recorder);
194 }
195 // TODO(ahe): Also enqueue type tests for closures.
196 }
197 }
198
199 void enqueueSelector(DynamicUse use) {
200 assert(use.mask == null);
201 Selector selector = use.selector;
202 if (enqueuedSelectors.add(selector)) {
203 pendingSelectors.add(selector);
204 }
205 }
206
207 void enqueueClosure(FunctionElement function, ClosureKind kind) {
208 Closurization closurization = new Closurization(function, kind);
209 if (implicitClosurizations.add(closurization)) {
210 pendingImplicitClosurizations.add(closurization);
211 }
212 }
213
214 void forgetElement(Element element) {
215 void revisitClass(ClassElement cls) {
216 if (instantiatedClasses.remove(cls)) {
217 // [cls] was already instantiated, now we need to make sure enqueue its
218 // members again in [enqueueInstanceMethods] above.
219 pendingInstantiatedClasses.add(cls);
220 }
221 }
222 if (!instantiatedClasses.remove(element)) {
223 // If a class is removed, the incremental compiler will first forget its
224 // members. This can move the class to pendingInstantiatedClasses.
225 pendingInstantiatedClasses.remove(element);
226 }
227 if (element.isInstanceMember) {
228 ClassElement modifiedClass = element.enclosingClass;
229 revisitClass(modifiedClass);
230 MemberElement member = element;
231 for (ClassElement cls in instantiatedClasses) {
232 // TODO(ahe): Make O(1).
233 if (cls.lookupByName(member.memberName) == member) {
234 revisitClass(cls);
235 // Once we have found one class that implements [member], we're
236 // done. When we later call [enqueueInstanceMethods] (via
237 // [FletchEnqueuer.processQueue]) the method will be enqueued again
238 // (if it exists).
239 break;
240 }
241 }
242 }
243 List<Closurization> toBeRemoved = <Closurization>[];
244 for (Closurization closurization in implicitClosurizations) {
245 if (closurization.function == element) {
246 toBeRemoved.add(closurization);
247 }
248 }
249 implicitClosurizations.removeAll(toBeRemoved);
250 }
251
252 void enqueueTypeTest(DartType type) {
253 type = type.asRaw();
254 switch (type.kind) {
255 case TypeKind.INTERFACE:
256 enqueueRawInterfaceType(type);
257 break;
258
259 default:
260 // Ignored.
261 break;
262 }
263 }
264
265 void enqueueRawInterfaceType(InterfaceType type) {
266 assert(type.isRaw);
267 if (typeTests.add(type)) {
268 pendingTypeTests.add(type);
269 }
270 }
271 }
272
273 /// Track that [function] is used as a closure. This can happen for various
274 /// reasons, see [ClosureKind] for more details. In practical terms, this means
275 /// that we need a class whose `call` method invokes [function]. For
276 /// [ClosureKind.functionLike], the class is a normal class with source
277 /// code. For most other kinds, the class is synthetic and doesn't have a
278 /// corresponding element.
279 class Closurization {
280 final FunctionElement function;
281
282 final ClosureKind kind;
283
284 final int hashCode;
285
286 Closurization(FunctionElement function, ClosureKind kind)
287 : function = function,
288 kind = kind,
289 hashCode = Hashing.mixHashCodeBits(function.hashCode, kind.hashCode);
290
291 bool operator ==(other) {
292 return other is Closurization &&
293 function == other.function && kind == other.kind;
294 }
295
296 String toString() => "Closurization($function, $kind)";
297 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/src/diagnostic.dart ('k') | pkg/fletchc/lib/src/enqueuer_mixin.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698