OLD | NEW |
| (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.fletch_enqueuer; | |
6 | |
7 import 'dart:collection' show | |
8 Queue; | |
9 | |
10 import 'package:compiler/src/common/tasks.dart' show | |
11 CompilerTask; | |
12 | |
13 import 'package:compiler/src/universe/world_impact.dart' show | |
14 WorldImpact; | |
15 | |
16 import 'package:compiler/src/types/types.dart' show | |
17 TypeMaskStrategy; | |
18 | |
19 import 'package:compiler/src/enqueue.dart' show | |
20 ResolutionEnqueuer, | |
21 CodegenEnqueuer, | |
22 TreeShakingEnqueuerStrategy; | |
23 | |
24 import 'package:compiler/src/compiler.dart' show | |
25 Compiler; | |
26 | |
27 import 'package:compiler/src/enqueue.dart' show | |
28 QueueFilter, | |
29 EnqueueTask, | |
30 Enqueuer; | |
31 | |
32 import 'package:compiler/src/universe/selector.dart' show | |
33 Selector; | |
34 | |
35 import 'package:compiler/src/universe/universe.dart' show | |
36 Universe; | |
37 | |
38 import 'package:compiler/src/dart_types.dart' show | |
39 DartType, | |
40 InterfaceType; | |
41 | |
42 import 'package:compiler/src/elements/elements.dart' show | |
43 AstElement, | |
44 ClassElement, | |
45 ConstructorElement, | |
46 Element, | |
47 FunctionElement, | |
48 LibraryElement, | |
49 LocalFunctionElement, | |
50 Name, | |
51 TypedElement; | |
52 | |
53 import 'package:compiler/src/resolution/tree_elements.dart' show | |
54 TreeElements; | |
55 | |
56 import 'package:compiler/src/util/util.dart' show | |
57 Hashing; | |
58 | |
59 import 'fletch_compiler_implementation.dart' show | |
60 FletchCompilerImplementation; | |
61 | |
62 import 'dynamic_call_enqueuer.dart' show | |
63 Closurization, | |
64 DynamicCallEnqueuer, | |
65 UsageRecorder; | |
66 | |
67 import 'fletch_registry.dart' show | |
68 ClosureKind, | |
69 FletchRegistry, | |
70 FletchRegistry; | |
71 | |
72 import 'dart:developer'; | |
73 import 'package:compiler/src/diagnostics/diagnostic_listener.dart'; | |
74 | |
75 import 'package:compiler/src/universe/use.dart' show | |
76 DynamicUse, | |
77 StaticUse; | |
78 | |
79 import 'package:compiler/src/universe/use.dart'; | |
80 import 'package:compiler/src/common/work.dart'; | |
81 import 'package:compiler/src/common/resolution.dart'; | |
82 import 'package:compiler/src/enqueue.dart'; | |
83 | |
84 part 'enqueuer_mixin.dart'; | |
85 | |
86 /// True if enqueuing of system libraries should be reported in verbose mode. | |
87 const bool logSystemLibraries = | |
88 const bool.fromEnvironment("fletchc.logSystemLibraries"); | |
89 | |
90 /// Returns true if enqueuing of [element] should be reported in verbose | |
91 /// mode. See [logSystemLibraries]. | |
92 bool shouldReportEnqueuingOfElement(Compiler compiler, Element element) { | |
93 if (logSystemLibraries) return true; | |
94 return compiler.inUserCode(element); | |
95 } | |
96 | |
97 /// Custom enqueuer for Fletch. | |
98 class FletchEnqueueTask extends CompilerTask implements EnqueueTask { | |
99 final ResolutionEnqueuer resolution; | |
100 | |
101 final FletchEnqueuer codegen; | |
102 | |
103 FletchEnqueueTask(FletchCompilerImplementation compiler) | |
104 : resolution = new ResolutionEnqueuer( | |
105 compiler, compiler.backend.createItemCompilationContext, | |
106 compiler.analyzeOnly && compiler.analyzeMain | |
107 ? const EnqueuerStrategy() : const TreeShakingEnqueuerStrategy()), | |
108 codegen = new FletchEnqueuer( | |
109 compiler, compiler.backend.createItemCompilationContext), | |
110 super(compiler) { | |
111 codegen.task = this; | |
112 resolution.task = this; | |
113 codegen.nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(codegen); | |
114 | |
115 resolution.nativeEnqueuer = | |
116 compiler.backend.nativeResolutionEnqueuer(resolution); | |
117 } | |
118 | |
119 String get name => 'Fletch enqueue'; | |
120 | |
121 void forgetElement(Element element) { | |
122 resolution.forgetElement(element); | |
123 codegen.forgetElement(element); | |
124 } | |
125 } | |
126 | |
127 class FletchEnqueuer extends EnqueuerMixin | |
128 implements CodegenEnqueuer, UsageRecorder { | |
129 final ItemCompilationContextCreator itemCompilationContextCreator; | |
130 | |
131 final FletchCompilerImplementation compiler; | |
132 | |
133 bool queueIsClosed = false; | |
134 | |
135 bool hasEnqueuedReflectiveElements = false; | |
136 | |
137 bool hasEnqueuedReflectiveStaticFields = false; | |
138 | |
139 EnqueueTask task; | |
140 | |
141 // TODO(ahe): Get rid of this? | |
142 var nativeEnqueuer; | |
143 | |
144 final Universe universe = new Universe(const TypeMaskStrategy()); | |
145 | |
146 final Set<ElementUsage> _enqueuedUsages = new Set<ElementUsage>(); | |
147 final Map<Element, List<ElementUsage>> _enqueuedUsagesByElement = | |
148 <Element, List<ElementUsage>>{}; | |
149 | |
150 final Queue<ElementUsage> _pendingEnqueuedUsages = | |
151 new Queue<ElementUsage>(); | |
152 | |
153 final Set<TypeTest> _typeTests = new Set<TypeTest>(); | |
154 | |
155 final Queue<TypeTest> _pendingTypeTests = new Queue<TypeTest>(); | |
156 | |
157 final DynamicCallEnqueuer dynamicCallEnqueuer; | |
158 | |
159 FletchEnqueuer( | |
160 FletchCompilerImplementation compiler, | |
161 this.itemCompilationContextCreator) | |
162 : compiler = compiler, | |
163 dynamicCallEnqueuer = new DynamicCallEnqueuer(compiler); | |
164 | |
165 bool get queueIsEmpty { | |
166 return _pendingEnqueuedUsages.isEmpty && _pendingTypeTests.isEmpty; | |
167 } | |
168 | |
169 bool get isResolutionQueue => false; | |
170 | |
171 QueueFilter get filter => compiler.enqueuerFilter; | |
172 | |
173 void forgetElement(Element element) { | |
174 List<ElementUsage> usages = _enqueuedUsagesByElement[element]; | |
175 if (usages != null) { | |
176 _enqueuedUsages.removeAll(usages); | |
177 } | |
178 dynamicCallEnqueuer.forgetElement(element); | |
179 } | |
180 | |
181 void registerInstantiatedType( | |
182 InterfaceType type, | |
183 {bool mirrorUsage: false}) { | |
184 dynamicCallEnqueuer.registerInstantiatedType(type); | |
185 } | |
186 | |
187 // TODO(ahe): Remove this method. | |
188 void registerStaticUse(StaticUse staticUse) { | |
189 _enqueueElement(staticUse.element, null, null); | |
190 } | |
191 | |
192 // TODO(ahe): Remove this method. | |
193 void addToWorkList(Element element) { | |
194 _enqueueElement(element, null, null); | |
195 } | |
196 | |
197 // TODO(ahe): Remove this method. | |
198 void forEach(_) { | |
199 processQueue(); | |
200 } | |
201 | |
202 void processQueue() { | |
203 do { | |
204 do { | |
205 while (!queueIsEmpty) { | |
206 if (!_pendingEnqueuedUsages.isEmpty) { | |
207 ElementUsage usage = _pendingEnqueuedUsages.removeFirst(); | |
208 AstElement element = usage.element; | |
209 TreeElements treeElements = element.resolvedAst.elements; | |
210 FletchRegistry registry = new FletchRegistry(compiler); | |
211 Selector selector = usage.selector; | |
212 if (usage.closureKind != null) { | |
213 compiler.context.backend.compileClosurizationUsage( | |
214 element, selector, treeElements, registry, usage.closureKind); | |
215 } else if (selector != null) { | |
216 compiler.context.backend.compileElementUsage( | |
217 element, selector, treeElements, registry); | |
218 } else { | |
219 compiler.context.backend.compileElement( | |
220 element, treeElements, registry); | |
221 } | |
222 } | |
223 if (!_pendingTypeTests.isEmpty) { | |
224 TypeTest test = _pendingTypeTests.removeFirst(); | |
225 compiler.context.backend.compileTypeTest(test.element, test.type); | |
226 } | |
227 } | |
228 dynamicCallEnqueuer.enqueueInstanceMethods(this); | |
229 } while (!queueIsEmpty); | |
230 // TODO(ahe): Pass recentClasses? | |
231 compiler.backend.onQueueEmpty(this, null); | |
232 } while (!queueIsEmpty); | |
233 } | |
234 | |
235 bool checkNoEnqueuedInvokedInstanceMethods() { | |
236 // TODO(ahe): Implement | |
237 return true; | |
238 } | |
239 | |
240 void logSummary(log(message)) { | |
241 // TODO(ahe): Implement this. | |
242 } | |
243 | |
244 void registerDynamicUse(DynamicUse use) { | |
245 dynamicCallEnqueuer.enqueueSelector(use); | |
246 } | |
247 | |
248 void applyImpact(Element element, WorldImpact worldImpact) { | |
249 assert(worldImpact == null); | |
250 } | |
251 | |
252 void registerIsCheck(DartType type) { | |
253 dynamicCallEnqueuer.enqueueTypeTest(type); | |
254 } | |
255 | |
256 void _enqueueElement( | |
257 Element element, | |
258 Selector selector, | |
259 ClosureKind closureKind) { | |
260 if (selector != null) { | |
261 _enqueueElement(element, null, null); | |
262 } else { | |
263 assert(closureKind == null); | |
264 } | |
265 ElementUsage usage = new ElementUsage(element, selector, closureKind); | |
266 if (_enqueuedUsages.add(usage)) { | |
267 _enqueuedUsagesByElement | |
268 .putIfAbsent(element, () => <ElementUsage>[]).add(usage); | |
269 _pendingEnqueuedUsages.addLast(usage); | |
270 if (shouldReportEnqueuingOfElement(compiler, element)) { | |
271 compiler.reportVerboseInfo(element, "called as $selector"); | |
272 } | |
273 } | |
274 } | |
275 | |
276 void recordElementUsage(Element element, Selector selector) { | |
277 if (!element.isParameter) { | |
278 _enqueueElement(element, selector, null); | |
279 } | |
280 } | |
281 | |
282 void recordClosurizationUsage( | |
283 Closurization closurization, | |
284 Selector selector) { | |
285 _enqueueElement(closurization.function, selector, closurization.kind); | |
286 } | |
287 | |
288 void recordTypeTest(ClassElement element, InterfaceType type) { | |
289 compiler.reportVerboseInfo(element, "type test $type"); | |
290 TypeTest test = new TypeTest(element, type); | |
291 if (_typeTests.add(test)) { | |
292 _pendingTypeTests.addLast(test); | |
293 } | |
294 } | |
295 } | |
296 | |
297 class ElementUsage { | |
298 final AstElement element; | |
299 | |
300 /// If selector is [null], this represents that [element] needs to be | |
301 /// compiled. | |
302 final Selector selector; | |
303 | |
304 final int hashCode; | |
305 | |
306 /// Non-null if this is a usage of [element] as a closure, for example, a | |
307 /// tear-off | |
308 final ClosureKind closureKind; | |
309 | |
310 ElementUsage(Element element, Selector selector, ClosureKind closureKind) | |
311 : element = element, | |
312 selector = selector, | |
313 closureKind = closureKind, | |
314 hashCode = Hashing.mixHashCodeBits( | |
315 Hashing.mixHashCodeBits(element.hashCode, selector.hashCode), | |
316 closureKind.hashCode); | |
317 | |
318 bool operator ==(other) { | |
319 return other is ElementUsage && | |
320 element == other.element && selector == other.selector && | |
321 closureKind == other.closureKind; | |
322 } | |
323 } | |
324 | |
325 class TypeTest { | |
326 final ClassElement element; | |
327 | |
328 final InterfaceType type; | |
329 | |
330 final int hashCode; | |
331 | |
332 TypeTest(ClassElement element, InterfaceType type) | |
333 : element = element, | |
334 type = type, | |
335 hashCode = Hashing.mixHashCodeBits(element.hashCode, type.hashCode); | |
336 | |
337 bool operator ==(other) { | |
338 return other is TypeTest && element == other.element && type == other.type; | |
339 } | |
340 } | |
OLD | NEW |