OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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.js.enqueue; | 5 library dart2js.js.enqueue; |
6 | 6 |
7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
8 | 8 |
9 import '../common/backend_api.dart' show Backend; | 9 import '../common/backend_api.dart' show Backend; |
10 import '../common/codegen.dart' show CodegenWorkItem; | 10 import '../common/codegen.dart' show CodegenWorkItem; |
(...skipping 30 matching lines...) Expand all Loading... | |
41 show ImpactUseCase, ImpactStrategy, WorldImpact, WorldImpactVisitor; | 41 show ImpactUseCase, ImpactStrategy, WorldImpact, WorldImpactVisitor; |
42 import '../util/util.dart' show Setlet; | 42 import '../util/util.dart' show Setlet; |
43 import '../world.dart'; | 43 import '../world.dart'; |
44 | 44 |
45 /// [Enqueuer] which is specific to code generation. | 45 /// [Enqueuer] which is specific to code generation. |
46 class CodegenEnqueuer extends EnqueuerImpl { | 46 class CodegenEnqueuer extends EnqueuerImpl { |
47 final String name; | 47 final String name; |
48 @deprecated | 48 @deprecated |
49 final Compiler _compiler; // TODO(ahe): Remove this dependency. | 49 final Compiler _compiler; // TODO(ahe): Remove this dependency. |
50 final EnqueuerStrategy strategy; | 50 final EnqueuerStrategy strategy; |
51 final Map<String, Set<Element>> instanceMembersByName = | 51 final Map<String, Set<Element>> _instanceMembersByName = |
52 new Map<String, Set<Element>>(); | 52 new Map<String, Set<Element>>(); |
53 final Map<String, Set<Element>> instanceFunctionsByName = | 53 final Map<String, Set<Element>> _instanceFunctionsByName = |
54 new Map<String, Set<Element>>(); | 54 new Map<String, Set<Element>>(); |
55 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); | 55 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); |
56 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); | 56 Set<ClassElement> _recentClasses = new Setlet<ClassElement>(); |
57 final CodegenWorldBuilderImpl _universe = | 57 final CodegenWorldBuilderImpl _universe = |
58 new CodegenWorldBuilderImpl(const TypeMaskStrategy()); | 58 new CodegenWorldBuilderImpl(const TypeMaskStrategy()); |
59 | 59 |
60 bool queueIsClosed = false; | 60 bool queueIsClosed = false; |
61 final CompilerTask task; | 61 final CompilerTask task; |
62 final native.NativeEnqueuer nativeEnqueuer; | 62 final native.NativeEnqueuer nativeEnqueuer; |
63 | 63 |
64 WorldImpactVisitor impactVisitor; | 64 WorldImpactVisitor _impactVisitor; |
65 | |
66 final Queue<WorkItem> queue = new Queue<WorkItem>(); | |
67 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; | |
68 | |
69 final Set<Element> newlyEnqueuedElements; | |
70 | |
71 final Set<DynamicUse> newlySeenSelectors; | |
72 | |
73 bool _enabledNoSuchMethod = false; | |
74 | |
75 static const ImpactUseCase IMPACT_USE = | |
76 const ImpactUseCase('CodegenEnqueuer'); | |
65 | 77 |
66 CodegenEnqueuer(this.task, Compiler compiler, this.strategy) | 78 CodegenEnqueuer(this.task, Compiler compiler, this.strategy) |
67 : queue = new Queue<CodegenWorkItem>(), | 79 : newlyEnqueuedElements = compiler.cacheStrategy.newSet(), |
68 newlyEnqueuedElements = compiler.cacheStrategy.newSet(), | |
69 newlySeenSelectors = compiler.cacheStrategy.newSet(), | 80 newlySeenSelectors = compiler.cacheStrategy.newSet(), |
70 nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(), | 81 nativeEnqueuer = compiler.backend.nativeCodegenEnqueuer(), |
71 this.name = 'codegen enqueuer', | 82 this.name = 'codegen enqueuer', |
72 this._compiler = compiler { | 83 this._compiler = compiler { |
73 impactVisitor = new EnqueuerImplImpactVisitor(this); | 84 _impactVisitor = new EnqueuerImplImpactVisitor(this); |
74 } | 85 } |
75 | 86 |
76 CodegenWorldBuilder get universe => _universe; | 87 CodegenWorldBuilder get universe => _universe; |
77 | 88 |
78 Backend get backend => _compiler.backend; | 89 Backend get _backend => _compiler.backend; |
79 | 90 |
80 CompilerOptions get options => _compiler.options; | 91 CompilerOptions get _options => _compiler.options; |
81 | 92 |
82 ClosedWorld get _world => _compiler.closedWorld; | 93 ClosedWorld get _world => _compiler.closedWorld; |
83 | 94 |
84 bool get queueIsEmpty => queue.isEmpty; | 95 bool get queueIsEmpty => queue.isEmpty; |
85 | 96 |
86 /// Returns [:true:] if this enqueuer is the resolution enqueuer. | 97 /// Returns [:true:] if this enqueuer is the resolution enqueuer. |
87 bool get isResolutionQueue => false; | 98 bool get isResolutionQueue => false; |
88 | 99 |
89 DiagnosticReporter get reporter => _compiler.reporter; | |
90 | |
91 /** | 100 /** |
92 * Documentation wanted -- johnniwinther | 101 * Documentation wanted -- johnniwinther |
93 * | 102 * |
94 * Invariant: [element] must be a declaration element. | 103 * Invariant: [element] must be a declaration element. |
95 */ | 104 */ |
96 void addToWorkList(Element element) { | 105 void _addToWorkList(Element element) { |
97 assert(invariant(element, element.isDeclaration)); | 106 assert(invariant(element, element.isDeclaration)); |
98 // Don't generate code for foreign elements. | 107 // Don't generate code for foreign elements. |
99 if (backend.isForeign(element)) return; | 108 if (_backend.isForeign(element)) return; |
100 | 109 |
101 // Codegen inlines field initializers. It only needs to generate | 110 // Codegen inlines field initializers. It only needs to generate |
102 // code for checked setters. | 111 // code for checked setters. |
103 if (element.isField && element.isInstanceMember) { | 112 if (element.isField && element.isInstanceMember) { |
104 if (!options.enableTypeAssertions || element.enclosingElement.isClosure) { | 113 if (!_options.enableTypeAssertions || |
114 element.enclosingElement.isClosure) { | |
105 return; | 115 return; |
106 } | 116 } |
107 } | 117 } |
108 | 118 |
109 if (options.hasIncrementalSupport && !isProcessed(element)) { | 119 if (_options.hasIncrementalSupport && !isProcessed(element)) { |
110 newlyEnqueuedElements.add(element); | 120 newlyEnqueuedElements.add(element); |
111 } | 121 } |
112 | 122 |
113 if (queueIsClosed) { | 123 if (queueIsClosed) { |
114 throw new SpannableAssertionFailure( | 124 throw new SpannableAssertionFailure( |
115 element, "Codegen work list is closed. Trying to add $element"); | 125 element, "Codegen work list is closed. Trying to add $element"); |
116 } | 126 } |
117 queue.add(new CodegenWorkItem(backend, element)); | 127 queue.add(new CodegenWorkItem(_backend, element)); |
118 // TODO(sigmund): add other missing dependencies (internals, selectors | 128 // TODO(sigmund): add other missing dependencies (internals, selectors |
119 // enqueued after allocations). | 129 // enqueued after allocations). |
120 _compiler.dumpInfoTask | 130 _compiler.dumpInfoTask |
121 .registerDependency(_compiler.currentElement, element); | 131 .registerDependency(_compiler.currentElement, element); |
122 } | 132 } |
123 | 133 |
124 void applyImpact(WorldImpact worldImpact, {Element impactSource}) { | 134 void applyImpact(WorldImpact worldImpact, {Element impactSource}) { |
125 if (worldImpact.isEmpty) return; | 135 if (worldImpact.isEmpty) return; |
126 impactStrategy.visitImpact( | 136 impactStrategy.visitImpact( |
127 impactSource, worldImpact, impactVisitor, impactUse); | 137 impactSource, worldImpact, _impactVisitor, impactUse); |
128 } | |
129 | |
130 void registerInstantiatedType(InterfaceType type) { | |
131 _registerInstantiatedType(type); | |
132 } | 138 } |
133 | 139 |
134 void _registerInstantiatedType(InterfaceType type, | 140 void _registerInstantiatedType(InterfaceType type, |
135 {bool mirrorUsage: false, bool nativeUsage: false}) { | 141 {bool mirrorUsage: false, bool nativeUsage: false}) { |
136 task.measure(() { | 142 task.measure(() { |
137 ClassElement cls = type.element; | 143 ClassElement cls = type.element; |
138 bool isNative = backend.isNative(cls); | 144 bool isNative = _backend.isNative(cls); |
139 _universe.registerTypeInstantiation(type, | 145 _universe.registerTypeInstantiation(type, |
140 isNative: isNative, | 146 isNative: isNative, |
141 byMirrors: mirrorUsage, onImplemented: (ClassElement cls) { | 147 byMirrors: mirrorUsage, onImplemented: (ClassElement cls) { |
142 applyImpact( | 148 applyImpact( |
143 backend.registerImplementedClass(cls, forResolution: false)); | 149 _backend.registerImplementedClass(cls, forResolution: false)); |
144 }); | 150 }); |
145 if (nativeUsage) { | 151 if (nativeUsage) { |
146 nativeEnqueuer.onInstantiatedType(type); | 152 nativeEnqueuer.onInstantiatedType(type); |
147 } | 153 } |
148 backend.registerInstantiatedType(type); | 154 _backend.registerInstantiatedType(type); |
149 // TODO(johnniwinther): Share this reasoning with [Universe]. | 155 // TODO(johnniwinther): Share this reasoning with [Universe]. |
150 if (!cls.isAbstract || isNative || mirrorUsage) { | 156 if (!cls.isAbstract || isNative || mirrorUsage) { |
151 processInstantiatedClass(cls); | 157 _processInstantiatedClass(cls); |
152 } | 158 } |
153 }); | 159 }); |
154 } | 160 } |
155 | 161 |
156 bool checkNoEnqueuedInvokedInstanceMethods() { | 162 bool checkNoEnqueuedInvokedInstanceMethods() { |
157 return strategy.checkEnqueuerConsistency(this); | 163 return strategy.checkEnqueuerConsistency(this); |
158 } | 164 } |
159 | 165 |
160 void processInstantiatedClassMembers(ClassElement cls) { | 166 void processInstantiatedClassMembers(ClassElement cls) { |
161 strategy.processInstantiatedClass(this, cls); | 167 strategy.processInstantiatedClass(this, cls); |
162 } | 168 } |
163 | 169 |
164 void processInstantiatedClassMember(ClassElement cls, Element member) { | 170 void processInstantiatedClassMember(ClassElement cls, Element member) { |
165 assert(invariant(member, member.isDeclaration)); | 171 assert(invariant(member, member.isDeclaration)); |
166 if (isProcessed(member)) return; | 172 if (isProcessed(member)) return; |
167 if (!member.isInstanceMember) return; | 173 if (!member.isInstanceMember) return; |
168 String memberName = member.name; | 174 String memberName = member.name; |
169 | 175 |
170 if (member.isField) { | 176 if (member.isField) { |
171 // The obvious thing to test here would be "member.isNative", | 177 // The obvious thing to test here would be "member.isNative", |
172 // however, that only works after metadata has been parsed/analyzed, | 178 // however, that only works after metadata has been parsed/analyzed, |
173 // and that may not have happened yet. | 179 // and that may not have happened yet. |
174 // So instead we use the enclosing class, which we know have had | 180 // So instead we use the enclosing class, which we know have had |
175 // its metadata parsed and analyzed. | 181 // its metadata parsed and analyzed. |
176 // Note: this assumes that there are no non-native fields on native | 182 // Note: this assumes that there are no non-native fields on native |
177 // classes, which may not be the case when a native class is subclassed. | 183 // classes, which may not be the case when a native class is subclassed. |
178 if (backend.isNative(cls)) { | 184 if (_backend.isNative(cls)) { |
179 if (_universe.hasInvokedGetter(member, _world) || | 185 if (_universe.hasInvokedGetter(member, _world) || |
180 _universe.hasInvocation(member, _world)) { | 186 _universe.hasInvocation(member, _world)) { |
181 addToWorkList(member); | 187 _addToWorkList(member); |
182 return; | 188 return; |
183 } else if (universe.hasInvokedSetter(member, _world)) { | 189 } else if (universe.hasInvokedSetter(member, _world)) { |
184 addToWorkList(member); | 190 _addToWorkList(member); |
185 return; | 191 return; |
186 } | 192 } |
187 // Native fields need to go into instanceMembersByName as they | 193 // Native fields need to go into instanceMembersByName as they |
188 // are virtual instantiation points and escape points. | 194 // are virtual instantiation points and escape points. |
189 } else { | 195 } else { |
190 // All field initializers must be resolved as they could | 196 // All field initializers must be resolved as they could |
191 // have an observable side-effect (and cannot be tree-shaken | 197 // have an observable side-effect (and cannot be tree-shaken |
192 // away). | 198 // away). |
193 addToWorkList(member); | 199 _addToWorkList(member); |
194 return; | 200 return; |
195 } | 201 } |
196 } else if (member.isFunction) { | 202 } else if (member.isFunction) { |
197 FunctionElement function = member; | 203 FunctionElement function = member; |
198 if (function.name == Identifiers.noSuchMethod_) { | 204 if (function.name == Identifiers.noSuchMethod_) { |
199 registerNoSuchMethod(function); | 205 _registerNoSuchMethod(function); |
200 } | 206 } |
201 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { | 207 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { |
202 registerCallMethodWithFreeTypeVariables(function); | 208 _registerCallMethodWithFreeTypeVariables(function); |
203 } | 209 } |
204 // If there is a property access with the same name as a method we | 210 // If there is a property access with the same name as a method we |
205 // need to emit the method. | 211 // need to emit the method. |
206 if (_universe.hasInvokedGetter(function, _world)) { | 212 if (_universe.hasInvokedGetter(function, _world)) { |
207 registerClosurizedMember(function); | 213 _registerClosurizedMember(function); |
208 addToWorkList(function); | 214 _addToWorkList(function); |
209 return; | 215 return; |
210 } | 216 } |
211 _registerInstanceMethod(function); | 217 _registerInstanceMethod(function); |
212 if (_universe.hasInvocation(function, _world)) { | 218 if (_universe.hasInvocation(function, _world)) { |
213 addToWorkList(function); | 219 _addToWorkList(function); |
214 return; | 220 return; |
215 } | 221 } |
216 } else if (member.isGetter) { | 222 } else if (member.isGetter) { |
217 FunctionElement getter = member; | 223 FunctionElement getter = member; |
218 if (_universe.hasInvokedGetter(getter, _world)) { | 224 if (_universe.hasInvokedGetter(getter, _world)) { |
219 addToWorkList(getter); | 225 _addToWorkList(getter); |
220 return; | 226 return; |
221 } | 227 } |
222 // We don't know what selectors the returned closure accepts. If | 228 // We don't know what selectors the returned closure accepts. If |
223 // the set contains any selector we have to assume that it matches. | 229 // the set contains any selector we have to assume that it matches. |
224 if (_universe.hasInvocation(getter, _world)) { | 230 if (_universe.hasInvocation(getter, _world)) { |
225 addToWorkList(getter); | 231 _addToWorkList(getter); |
226 return; | 232 return; |
227 } | 233 } |
228 } else if (member.isSetter) { | 234 } else if (member.isSetter) { |
229 FunctionElement setter = member; | 235 FunctionElement setter = member; |
230 if (_universe.hasInvokedSetter(setter, _world)) { | 236 if (_universe.hasInvokedSetter(setter, _world)) { |
231 addToWorkList(setter); | 237 _addToWorkList(setter); |
232 return; | 238 return; |
233 } | 239 } |
234 } | 240 } |
235 | 241 |
236 // The element is not yet used. Add it to the list of instance | 242 // The element is not yet used. Add it to the list of instance |
237 // members to still be processed. | 243 // members to still be processed. |
238 instanceMembersByName | 244 _instanceMembersByName |
239 .putIfAbsent(memberName, () => new Set<Element>()) | 245 .putIfAbsent(memberName, () => new Set<Element>()) |
240 .add(member); | 246 .add(member); |
241 } | 247 } |
242 | 248 |
243 // Store the member in [instanceFunctionsByName] to catch | 249 // Store the member in [instanceFunctionsByName] to catch |
244 // getters on the function. | 250 // getters on the function. |
245 void _registerInstanceMethod(MethodElement element) { | 251 void _registerInstanceMethod(MethodElement element) { |
246 instanceFunctionsByName | 252 _instanceFunctionsByName |
247 .putIfAbsent(element.name, () => new Set<Element>()) | 253 .putIfAbsent(element.name, () => new Set<Element>()) |
248 .add(element); | 254 .add(element); |
249 } | 255 } |
250 | 256 |
251 void enableIsolateSupport() {} | 257 void _processInstantiatedClass(ClassElement cls) { |
Harry Terkelsen
2016/11/29 22:25:03
can we remove all enableIsolateSupport calls?
Johnni Winther
2016/11/30 08:05:23
This is only for the codegen enqueuer. The resolut
| |
252 | |
253 void processInstantiatedClass(ClassElement cls) { | |
254 task.measure(() { | 258 task.measure(() { |
255 if (_processedClasses.contains(cls)) return; | 259 if (_processedClasses.contains(cls)) return; |
256 | 260 |
257 void processClass(ClassElement superclass) { | 261 void processClass(ClassElement superclass) { |
258 if (_processedClasses.contains(superclass)) return; | 262 if (_processedClasses.contains(superclass)) return; |
259 // TODO(johnniwinther): Re-insert this invariant when unittests don't | 263 // TODO(johnniwinther): Re-insert this invariant when unittests don't |
260 // fail. There is already a similar invariant on the members. | 264 // fail. There is already a similar invariant on the members. |
261 /*assert(invariant(superclass, | 265 /*assert(invariant(superclass, |
262 superclass.isClosure || | 266 superclass.isClosure || |
263 _compiler.enqueuer.resolution.isClassProcessed(superclass), | 267 _compiler.enqueuer.resolution.isClassProcessed(superclass), |
264 message: "Class $superclass has not been " | 268 message: "Class $superclass has not been " |
265 "processed in resolution.")); | 269 "processed in resolution.")); |
266 */ | 270 */ |
267 | 271 |
268 _processedClasses.add(superclass); | 272 _processedClasses.add(superclass); |
269 recentClasses.add(superclass); | 273 _recentClasses.add(superclass); |
270 superclass.implementation.forEachMember(processInstantiatedClassMember); | 274 superclass.implementation.forEachMember(processInstantiatedClassMember); |
271 // We only tell the backend once that [superclass] was instantiated, so | 275 // We only tell the backend once that [superclass] was instantiated, so |
272 // any additional dependencies must be treated as global | 276 // any additional dependencies must be treated as global |
273 // dependencies. | 277 // dependencies. |
274 applyImpact(backend.registerInstantiatedClass(superclass, | 278 applyImpact(_backend.registerInstantiatedClass(superclass, |
275 forResolution: false)); | 279 forResolution: false)); |
276 } | 280 } |
277 | 281 |
278 ClassElement superclass = cls; | 282 ClassElement superclass = cls; |
279 while (superclass != null) { | 283 while (superclass != null) { |
280 processClass(superclass); | 284 processClass(superclass); |
281 superclass = superclass.superclass; | 285 superclass = superclass.superclass; |
282 } | 286 } |
283 }); | 287 }); |
284 } | 288 } |
285 | 289 |
286 void registerDynamicUse(DynamicUse dynamicUse) { | 290 void processDynamicUse(DynamicUse dynamicUse) { |
287 task.measure(() { | 291 task.measure(() { |
288 if (_universe.registerDynamicUse(dynamicUse)) { | 292 if (_universe.registerDynamicUse(dynamicUse)) { |
289 handleUnseenSelector(dynamicUse); | 293 _handleUnseenSelector(dynamicUse); |
290 } | 294 } |
291 }); | 295 }); |
292 } | 296 } |
293 | 297 |
294 void processSet( | 298 void _processSet( |
295 Map<String, Set<Element>> map, String memberName, bool f(Element e)) { | 299 Map<String, Set<Element>> map, String memberName, bool f(Element e)) { |
296 Set<Element> members = map[memberName]; | 300 Set<Element> members = map[memberName]; |
297 if (members == null) return; | 301 if (members == null) return; |
298 // [f] might add elements to [: map[memberName] :] during the loop below | 302 // [f] might add elements to [: map[memberName] :] during the loop below |
299 // so we create a new list for [: map[memberName] :] and prepend the | 303 // so we create a new list for [: map[memberName] :] and prepend the |
300 // [remaining] members after the loop. | 304 // [remaining] members after the loop. |
301 map[memberName] = new Set<Element>(); | 305 map[memberName] = new Set<Element>(); |
302 Set<Element> remaining = new Set<Element>(); | 306 Set<Element> remaining = new Set<Element>(); |
303 for (Element member in members) { | 307 for (Element member in members) { |
304 if (!f(member)) remaining.add(member); | 308 if (!f(member)) remaining.add(member); |
305 } | 309 } |
306 map[memberName].addAll(remaining); | 310 map[memberName].addAll(remaining); |
307 } | 311 } |
308 | 312 |
309 processInstanceMembers(String n, bool f(Element e)) { | 313 void _processInstanceMembers(String n, bool f(Element e)) { |
310 processSet(instanceMembersByName, n, f); | 314 _processSet(_instanceMembersByName, n, f); |
311 } | 315 } |
312 | 316 |
313 processInstanceFunctions(String n, bool f(Element e)) { | 317 void _processInstanceFunctions(String n, bool f(Element e)) { |
314 processSet(instanceFunctionsByName, n, f); | 318 _processSet(_instanceFunctionsByName, n, f); |
315 } | 319 } |
316 | 320 |
317 void _handleUnseenSelector(DynamicUse universeSelector) { | 321 void _handleUnseenSelector(DynamicUse dynamicUse) { |
318 strategy.processDynamicUse(this, universeSelector); | 322 if (_options.hasIncrementalSupport) { |
319 } | 323 newlySeenSelectors.add(dynamicUse); |
320 | 324 } |
321 void handleUnseenSelectorInternal(DynamicUse dynamicUse) { | |
322 Selector selector = dynamicUse.selector; | 325 Selector selector = dynamicUse.selector; |
323 String methodName = selector.name; | 326 String methodName = selector.name; |
324 processInstanceMembers(methodName, (Element member) { | 327 _processInstanceMembers(methodName, (Element member) { |
325 if (dynamicUse.appliesUnnamed(member, _world)) { | 328 if (dynamicUse.appliesUnnamed(member, _world)) { |
326 if (member.isFunction && selector.isGetter) { | 329 if (member.isFunction && selector.isGetter) { |
327 registerClosurizedMember(member); | 330 _registerClosurizedMember(member); |
328 } | 331 } |
329 addToWorkList(member); | 332 _addToWorkList(member); |
330 return true; | 333 return true; |
331 } | 334 } |
332 return false; | 335 return false; |
333 }); | 336 }); |
334 if (selector.isGetter) { | 337 if (selector.isGetter) { |
335 processInstanceFunctions(methodName, (Element member) { | 338 _processInstanceFunctions(methodName, (Element member) { |
336 if (dynamicUse.appliesUnnamed(member, _world)) { | 339 if (dynamicUse.appliesUnnamed(member, _world)) { |
337 registerClosurizedMember(member); | 340 _registerClosurizedMember(member); |
338 return true; | 341 return true; |
339 } | 342 } |
340 return false; | 343 return false; |
341 }); | 344 }); |
342 } | 345 } |
343 } | 346 } |
344 | 347 |
345 /** | 348 void processStaticUse(StaticUse staticUse) { |
346 * Documentation wanted -- johnniwinther | |
347 * | |
348 * Invariant: [element] must be a declaration element. | |
349 */ | |
350 void registerStaticUse(StaticUse staticUse) { | |
351 strategy.processStaticUse(this, staticUse); | |
352 } | |
353 | |
354 void registerStaticUseInternal(StaticUse staticUse) { | |
355 Element element = staticUse.element; | 349 Element element = staticUse.element; |
356 assert(invariant(element, element.isDeclaration, | 350 assert(invariant(element, element.isDeclaration, |
357 message: "Element ${element} is not the declaration.")); | 351 message: "Element ${element} is not the declaration.")); |
358 _universe.registerStaticUse(staticUse); | 352 _universe.registerStaticUse(staticUse); |
359 applyImpact(backend.registerStaticUse(element, forResolution: false)); | 353 applyImpact(_backend.registerStaticUse(element, forResolution: false)); |
360 bool addElement = true; | 354 bool addElement = true; |
361 switch (staticUse.kind) { | 355 switch (staticUse.kind) { |
362 case StaticUseKind.STATIC_TEAR_OFF: | 356 case StaticUseKind.STATIC_TEAR_OFF: |
363 applyImpact(backend.registerGetOfStaticFunction()); | 357 applyImpact(_backend.registerGetOfStaticFunction()); |
364 break; | 358 break; |
365 case StaticUseKind.FIELD_GET: | 359 case StaticUseKind.FIELD_GET: |
366 case StaticUseKind.FIELD_SET: | 360 case StaticUseKind.FIELD_SET: |
367 case StaticUseKind.CLOSURE: | 361 case StaticUseKind.CLOSURE: |
368 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and | 362 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and |
369 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. | 363 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. |
370 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot | 364 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot |
371 // enqueue. | 365 // enqueue. |
372 addElement = false; | 366 addElement = false; |
373 break; | 367 break; |
374 case StaticUseKind.SUPER_FIELD_SET: | 368 case StaticUseKind.SUPER_FIELD_SET: |
375 case StaticUseKind.SUPER_TEAR_OFF: | 369 case StaticUseKind.SUPER_TEAR_OFF: |
376 case StaticUseKind.GENERAL: | 370 case StaticUseKind.GENERAL: |
377 case StaticUseKind.DIRECT_USE: | 371 case StaticUseKind.DIRECT_USE: |
378 break; | 372 break; |
379 case StaticUseKind.CONSTRUCTOR_INVOKE: | 373 case StaticUseKind.CONSTRUCTOR_INVOKE: |
380 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: | 374 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: |
381 case StaticUseKind.REDIRECTION: | 375 case StaticUseKind.REDIRECTION: |
382 registerTypeUseInternal(new TypeUse.instantiation(staticUse.type)); | 376 processTypeUse(new TypeUse.instantiation(staticUse.type)); |
383 break; | 377 break; |
384 case StaticUseKind.DIRECT_INVOKE: | 378 case StaticUseKind.DIRECT_INVOKE: |
385 _registerInstanceMethod(staticUse.element); | 379 _registerInstanceMethod(staticUse.element); |
386 break; | 380 break; |
387 } | 381 } |
388 if (addElement) { | 382 if (addElement) { |
389 addToWorkList(element); | 383 _addToWorkList(element); |
390 } | 384 } |
391 } | 385 } |
392 | 386 |
393 void registerTypeUse(TypeUse typeUse) { | 387 void processTypeUse(TypeUse typeUse) { |
394 strategy.processTypeUse(this, typeUse); | |
395 } | |
396 | |
397 void registerTypeUseInternal(TypeUse typeUse) { | |
398 DartType type = typeUse.type; | 388 DartType type = typeUse.type; |
399 switch (typeUse.kind) { | 389 switch (typeUse.kind) { |
400 case TypeUseKind.INSTANTIATION: | 390 case TypeUseKind.INSTANTIATION: |
401 _registerInstantiatedType(type); | 391 _registerInstantiatedType(type); |
402 break; | 392 break; |
403 case TypeUseKind.MIRROR_INSTANTIATION: | 393 case TypeUseKind.MIRROR_INSTANTIATION: |
404 _registerInstantiatedType(type, mirrorUsage: true); | 394 _registerInstantiatedType(type, mirrorUsage: true); |
405 break; | 395 break; |
406 case TypeUseKind.NATIVE_INSTANTIATION: | 396 case TypeUseKind.NATIVE_INSTANTIATION: |
407 _registerInstantiatedType(type, nativeUsage: true); | 397 _registerInstantiatedType(type, nativeUsage: true); |
408 break; | 398 break; |
409 case TypeUseKind.IS_CHECK: | 399 case TypeUseKind.IS_CHECK: |
410 case TypeUseKind.AS_CAST: | 400 case TypeUseKind.AS_CAST: |
411 case TypeUseKind.CATCH_TYPE: | 401 case TypeUseKind.CATCH_TYPE: |
412 _registerIsCheck(type); | 402 _registerIsCheck(type); |
413 break; | 403 break; |
414 case TypeUseKind.CHECKED_MODE_CHECK: | 404 case TypeUseKind.CHECKED_MODE_CHECK: |
415 if (options.enableTypeAssertions) { | 405 if (_options.enableTypeAssertions) { |
416 _registerIsCheck(type); | 406 _registerIsCheck(type); |
417 } | 407 } |
418 break; | 408 break; |
419 case TypeUseKind.TYPE_LITERAL: | 409 case TypeUseKind.TYPE_LITERAL: |
420 break; | 410 break; |
421 } | 411 } |
422 } | 412 } |
423 | 413 |
424 void _registerIsCheck(DartType type) { | 414 void _registerIsCheck(DartType type) { |
425 type = _universe.registerIsCheck(type, _compiler.resolution); | 415 type = _universe.registerIsCheck(type, _compiler.resolution); |
426 // Even in checked mode, type annotations for return type and argument | 416 // Even in checked mode, type annotations for return type and argument |
427 // types do not imply type checks, so there should never be a check | 417 // types do not imply type checks, so there should never be a check |
428 // against the type variable of a typedef. | 418 // against the type variable of a typedef. |
429 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); | 419 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); |
430 } | 420 } |
431 | 421 |
432 void registerCallMethodWithFreeTypeVariables(Element element) { | 422 void _registerCallMethodWithFreeTypeVariables(Element element) { |
433 applyImpact(backend.registerCallMethodWithFreeTypeVariables(element, | 423 applyImpact(_backend.registerCallMethodWithFreeTypeVariables(element, |
434 forResolution: false)); | 424 forResolution: false)); |
435 } | 425 } |
436 | 426 |
437 void registerClosurizedMember(TypedElement element) { | 427 void _registerClosurizedMember(TypedElement element) { |
438 assert(element.isInstanceMember); | 428 assert(element.isInstanceMember); |
439 if (element.type.containsTypeVariables) { | 429 if (element.type.containsTypeVariables) { |
440 applyImpact(backend.registerClosureWithFreeTypeVariables(element, | 430 applyImpact(_backend.registerClosureWithFreeTypeVariables(element, |
441 forResolution: false)); | 431 forResolution: false)); |
442 } | 432 } |
443 applyImpact(backend.registerBoundClosure()); | 433 applyImpact(_backend.registerBoundClosure()); |
444 } | 434 } |
445 | 435 |
446 void forEach(void f(WorkItem work)) { | 436 void forEach(void f(WorkItem work)) { |
447 do { | 437 do { |
448 while (queue.isNotEmpty) { | 438 while (queue.isNotEmpty) { |
449 // TODO(johnniwinther): Find an optimal process order. | 439 // TODO(johnniwinther): Find an optimal process order. |
450 WorkItem work = queue.removeLast(); | 440 WorkItem work = queue.removeLast(); |
451 if (!isProcessed(work.element)) { | 441 if (!isProcessed(work.element)) { |
452 strategy.processWorkItem(f, work); | 442 strategy.processWorkItem(f, work); |
453 // TODO(johnniwinther): Register the processed element here. This | 443 // TODO(johnniwinther): Register the processed element here. This |
454 // is currently a side-effect of calling `work.run`. | 444 // is currently a side-effect of calling `work.run`. |
455 } | 445 } |
456 } | 446 } |
457 List recents = recentClasses.toList(growable: false); | 447 List recents = _recentClasses.toList(growable: false); |
458 recentClasses.clear(); | 448 _recentClasses.clear(); |
459 if (!onQueueEmpty(recents)) recentClasses.addAll(recents); | 449 if (!_onQueueEmpty(recents)) _recentClasses.addAll(recents); |
460 } while (queue.isNotEmpty || recentClasses.isNotEmpty); | 450 } while (queue.isNotEmpty || _recentClasses.isNotEmpty); |
461 } | 451 } |
462 | 452 |
463 /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses] | 453 /// [_onQueueEmpty] is called whenever the queue is drained. [recentClasses] |
464 /// contains the set of all classes seen for the first time since | 454 /// contains the set of all classes seen for the first time since |
465 /// [onQueueEmpty] was called last. A return value of [true] indicates that | 455 /// [_onQueueEmpty] was called last. A return value of [true] indicates that |
466 /// the [recentClasses] have been processed and may be cleared. If [false] is | 456 /// the [recentClasses] have been processed and may be cleared. If [false] is |
467 /// returned, [onQueueEmpty] will be called once the queue is empty again (or | 457 /// returned, [_onQueueEmpty] will be called once the queue is empty again (or |
468 /// still empty) and [recentClasses] will be a superset of the current value. | 458 /// still empty) and [recentClasses] will be a superset of the current value. |
469 bool onQueueEmpty(Iterable<ClassElement> recentClasses) { | 459 bool _onQueueEmpty(Iterable<ClassElement> recentClasses) { |
470 return backend.onQueueEmpty(this, recentClasses); | 460 return _backend.onQueueEmpty(this, recentClasses); |
471 } | 461 } |
472 | 462 |
473 void logSummary(log(message)) { | 463 void logSummary(log(message)) { |
474 _logSpecificSummary(log); | 464 log('Compiled ${generatedCode.length} methods.'); |
475 nativeEnqueuer.logSummary(log); | 465 nativeEnqueuer.logSummary(log); |
476 } | 466 } |
477 | 467 |
478 String toString() => 'Enqueuer($name)'; | 468 String toString() => 'Enqueuer($name)'; |
479 | 469 |
480 void _forgetElement(Element element) { | 470 void _forgetElement(Element element) { |
481 _universe.forgetElement(element, _compiler); | 471 _universe.forgetElement(element, _compiler); |
482 _processedClasses.remove(element); | 472 _processedClasses.remove(element); |
483 instanceMembersByName[element.name]?.remove(element); | 473 _instanceMembersByName[element.name]?.remove(element); |
484 instanceFunctionsByName[element.name]?.remove(element); | 474 _instanceFunctionsByName[element.name]?.remove(element); |
485 } | 475 } |
486 | 476 |
487 final Queue<CodegenWorkItem> queue; | |
488 final Map<Element, js.Expression> generatedCode = <Element, js.Expression>{}; | |
489 | |
490 final Set<Element> newlyEnqueuedElements; | |
491 | |
492 final Set<DynamicUse> newlySeenSelectors; | |
493 | |
494 bool enabledNoSuchMethod = false; | |
495 | |
496 static const ImpactUseCase IMPACT_USE = | |
497 const ImpactUseCase('CodegenEnqueuer'); | |
498 | |
499 ImpactUseCase get impactUse => IMPACT_USE; | 477 ImpactUseCase get impactUse => IMPACT_USE; |
500 | 478 |
501 bool isProcessed(Element member) => | 479 bool isProcessed(Element member) => |
502 member.isAbstract || generatedCode.containsKey(member); | 480 member.isAbstract || generatedCode.containsKey(member); |
503 | 481 |
504 void registerNoSuchMethod(Element element) { | 482 void _registerNoSuchMethod(Element element) { |
505 if (!enabledNoSuchMethod && backend.enabledNoSuchMethod) { | 483 if (!_enabledNoSuchMethod && _backend.enabledNoSuchMethod) { |
506 applyImpact(backend.enableNoSuchMethod()); | 484 applyImpact(_backend.enableNoSuchMethod()); |
507 enabledNoSuchMethod = true; | 485 _enabledNoSuchMethod = true; |
508 } | 486 } |
509 } | 487 } |
510 | 488 |
511 void _logSpecificSummary(log(message)) { | |
512 log('Compiled ${generatedCode.length} methods.'); | |
513 } | |
514 | |
515 void forgetElement(Element element, Compiler compiler) { | 489 void forgetElement(Element element, Compiler compiler) { |
516 _forgetElement(element); | 490 _forgetElement(element); |
517 generatedCode.remove(element); | 491 generatedCode.remove(element); |
518 if (element is MemberElement) { | 492 if (element is MemberElement) { |
519 for (Element closure in element.nestedClosures) { | 493 for (Element closure in element.nestedClosures) { |
520 generatedCode.remove(closure); | 494 generatedCode.remove(closure); |
521 removeFromSet(instanceMembersByName, closure); | 495 removeFromSet(_instanceMembersByName, closure); |
522 removeFromSet(instanceFunctionsByName, closure); | 496 removeFromSet(_instanceFunctionsByName, closure); |
523 } | 497 } |
524 } | 498 } |
525 } | 499 } |
526 | 500 |
527 void handleUnseenSelector(DynamicUse dynamicUse) { | |
528 if (options.hasIncrementalSupport) { | |
529 newlySeenSelectors.add(dynamicUse); | |
530 } | |
531 _handleUnseenSelector(dynamicUse); | |
532 } | |
533 | |
534 @override | 501 @override |
535 Iterable<Entity> get processedEntities => generatedCode.keys; | 502 Iterable<Entity> get processedEntities => generatedCode.keys; |
536 | 503 |
537 @override | 504 @override |
538 Iterable<ClassElement> get processedClasses => _processedClasses; | 505 Iterable<ClassElement> get processedClasses => _processedClasses; |
539 } | 506 } |
540 | 507 |
541 void removeFromSet(Map<String, Set<Element>> map, Element element) { | 508 void removeFromSet(Map<String, Set<Element>> map, Element element) { |
542 Set<Element> set = map[element.name]; | 509 Set<Element> set = map[element.name]; |
543 if (set == null) return; | 510 if (set == null) return; |
544 set.remove(element); | 511 set.remove(element); |
545 } | 512 } |
OLD | NEW |