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

Side by Side Diff: pkg/compiler/lib/src/enqueue.dart

Issue 2535143003: More refactoring of enqueuers (Closed)
Patch Set: Created 4 years 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
OLDNEW
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.enqueue; 5 library dart2js.enqueue;
6 6
7 import 'dart:collection' show Queue; 7 import 'dart:collection' show Queue;
8 8
9 import 'cache_strategy.dart'; 9 import 'cache_strategy.dart';
10 import 'common/backend_api.dart' show Backend; 10 import 'common/backend_api.dart' show Backend;
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 /// Returns [:true:] if [member] has been processed by this enqueuer. 114 /// Returns [:true:] if [member] has been processed by this enqueuer.
115 bool isProcessed(Element member); 115 bool isProcessed(Element member);
116 116
117 Iterable<Entity> get processedEntities; 117 Iterable<Entity> get processedEntities;
118 118
119 Iterable<ClassElement> get processedClasses; 119 Iterable<ClassElement> get processedClasses;
120 } 120 }
121 121
122 abstract class EnqueuerImpl extends Enqueuer { 122 abstract class EnqueuerImpl extends Enqueuer {
123 CompilerTask get task; 123 CompilerTask get task;
124 EnqueuerStrategy get strategy;
124 void processInstantiatedClassMembers(ClassElement cls); 125 void processInstantiatedClassMembers(ClassElement cls);
125 void processInstantiatedClassMember(ClassElement cls, Element member); 126 void processInstantiatedClassMember(ClassElement cls, Element member);
126 void registerStaticUse(StaticUse staticUse); 127 void processStaticUse(StaticUse staticUse);
127 void registerStaticUseInternal(StaticUse staticUse); 128 void processTypeUse(TypeUse typeUse);
128 void registerTypeUse(TypeUse typeUse); 129 void processDynamicUse(DynamicUse dynamicUse);
129 void registerTypeUseInternal(TypeUse typeUse);
130 void registerDynamicUse(DynamicUse dynamicUse);
131 void handleUnseenSelectorInternal(DynamicUse dynamicUse);
132 } 130 }
133 131
134 /// [Enqueuer] which is specific to resolution. 132 /// [Enqueuer] which is specific to resolution.
135 class ResolutionEnqueuer extends EnqueuerImpl { 133 class ResolutionEnqueuer extends EnqueuerImpl {
134 static const ImpactUseCase IMPACT_USE =
135 const ImpactUseCase('ResolutionEnqueuer');
136
136 final CompilerTask task; 137 final CompilerTask task;
137 final String name; 138 final String name;
138 final Resolution resolution; 139 final Resolution _resolution;
139 final CompilerOptions options; 140 final CompilerOptions _options;
140 final Backend backend; 141 final Backend backend;
141 final GlobalDependencyRegistry globalDependencies; 142 final GlobalDependencyRegistry _globalDependencies;
142 final CommonElements commonElements; 143 final CommonElements _commonElements;
143 final native.NativeEnqueuer nativeEnqueuer; 144 final native.NativeEnqueuer nativeEnqueuer;
144 145
145 final EnqueuerStrategy strategy; 146 final EnqueuerStrategy strategy;
146 final Map<String, Set<Element>> instanceMembersByName = 147 final Map<String, Set<Element>> _instanceMembersByName =
147 new Map<String, Set<Element>>(); 148 new Map<String, Set<Element>>();
148 final Map<String, Set<Element>> instanceFunctionsByName = 149 final Map<String, Set<Element>> _instanceFunctionsByName =
149 new Map<String, Set<Element>>(); 150 new Map<String, Set<Element>>();
150 final Set<ClassElement> _processedClasses = new Set<ClassElement>(); 151 final Set<ClassElement> _processedClasses = new Set<ClassElement>();
151 Set<ClassElement> recentClasses = new Setlet<ClassElement>(); 152 Set<ClassElement> _recentClasses = new Setlet<ClassElement>();
152 final ResolutionWorldBuilderImpl _universe; 153 final ResolutionWorldBuilderImpl _universe;
153 154
154 bool queueIsClosed = false; 155 bool queueIsClosed = false;
155 156
156 WorldImpactVisitor impactVisitor; 157 WorldImpactVisitor _impactVisitor;
158
159 /// All declaration elements that have been processed by the resolver.
160 final Set<AstElement> processedElements = new Set<AstElement>();
161
162 final Queue<WorkItem> _queue = new Queue<WorkItem>();
163
164 /// Queue of deferred resolution actions to execute when the resolution queue
165 /// has been emptied.
166 final Queue<_DeferredAction> _deferredQueue = new Queue<_DeferredAction>();
157 167
158 ResolutionEnqueuer( 168 ResolutionEnqueuer(
159 this.task, 169 this.task,
160 this.options, 170 this._options,
161 this.resolution, 171 this._resolution,
162 this.strategy, 172 this.strategy,
163 this.globalDependencies, 173 this._globalDependencies,
164 Backend backend, 174 Backend backend,
165 CommonElements commonElements, 175 CommonElements commonElements,
166 CacheStrategy cacheStrategy, 176 CacheStrategy cacheStrategy,
167 [this.name = 'resolution enqueuer']) 177 [this.name = 'resolution enqueuer'])
168 : this.backend = backend, 178 : this.backend = backend,
169 this.commonElements = commonElements, 179 this._commonElements = commonElements,
170 this.nativeEnqueuer = backend.nativeResolutionEnqueuer(), 180 this.nativeEnqueuer = backend.nativeResolutionEnqueuer(),
171 processedElements = new Set<AstElement>(),
172 queue = new Queue<ResolutionWorkItem>(),
173 deferredQueue = new Queue<_DeferredAction>(),
174 _universe = new ResolutionWorldBuilderImpl( 181 _universe = new ResolutionWorldBuilderImpl(
175 backend, commonElements, cacheStrategy, const TypeMaskStrategy()) { 182 backend, commonElements, cacheStrategy, const TypeMaskStrategy()) {
176 impactVisitor = new EnqueuerImplImpactVisitor(this); 183 _impactVisitor = new EnqueuerImplImpactVisitor(this);
177 } 184 }
178 185
179 ResolutionWorldBuilder get universe => _universe; 186 ResolutionWorldBuilder get universe => _universe;
180 187
181 OpenWorld get openWorld => universe.openWorld; 188 OpenWorld get _openWorld => universe.openWorld;
182 189
183 bool get queueIsEmpty => queue.isEmpty; 190 bool get queueIsEmpty => _queue.isEmpty;
184 191
185 DiagnosticReporter get reporter => resolution.reporter; 192 DiagnosticReporter get _reporter => _resolution.reporter;
186
187 bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls);
188 193
189 Iterable<ClassElement> get processedClasses => _processedClasses; 194 Iterable<ClassElement> get processedClasses => _processedClasses;
190 195
191 /**
192 * Documentation wanted -- johnniwinther
193 *
194 * Invariant: [element] must be a declaration element.
195 */
196 void addToWorkList(Element element) {
197 assert(invariant(element, element.isDeclaration));
198 internalAddToWorkList(element);
199 }
200
201 void applyImpact(WorldImpact worldImpact, {Element impactSource}) { 196 void applyImpact(WorldImpact worldImpact, {Element impactSource}) {
202 if (worldImpact.isEmpty) return; 197 if (worldImpact.isEmpty) return;
203 impactStrategy.visitImpact( 198 impactStrategy.visitImpact(
204 impactSource, worldImpact, impactVisitor, impactUse); 199 impactSource, worldImpact, _impactVisitor, impactUse);
205 }
206
207 void registerInstantiatedType(InterfaceType type) {
208 _registerInstantiatedType(type, globalDependency: true);
209 } 200 }
210 201
211 void _registerInstantiatedType(InterfaceType type, 202 void _registerInstantiatedType(InterfaceType type,
212 {ConstructorElement constructor, 203 {ConstructorElement constructor,
213 bool mirrorUsage: false, 204 bool mirrorUsage: false,
214 bool nativeUsage: false, 205 bool nativeUsage: false,
215 bool globalDependency: false, 206 bool globalDependency: false,
216 bool isRedirection: false}) { 207 bool isRedirection: false}) {
217 task.measure(() { 208 task.measure(() {
218 ClassElement cls = type.element; 209 ClassElement cls = type.element;
219 cls.ensureResolved(resolution); 210 cls.ensureResolved(_resolution);
220 bool isNative = backend.isNative(cls); 211 bool isNative = backend.isNative(cls);
221 _universe.registerTypeInstantiation(type, 212 _universe.registerTypeInstantiation(type,
222 constructor: constructor, 213 constructor: constructor,
223 isNative: isNative, 214 isNative: isNative,
224 byMirrors: mirrorUsage, 215 byMirrors: mirrorUsage,
225 isRedirection: isRedirection, onImplemented: (ClassElement cls) { 216 isRedirection: isRedirection, onImplemented: (ClassElement cls) {
226 applyImpact(backend.registerImplementedClass(cls, forResolution: true)); 217 applyImpact(backend.registerImplementedClass(cls, forResolution: true));
227 }); 218 });
228 if (globalDependency && !mirrorUsage) { 219 if (globalDependency && !mirrorUsage) {
229 globalDependencies.registerDependency(type.element); 220 _globalDependencies.registerDependency(type.element);
230 } 221 }
231 if (nativeUsage) { 222 if (nativeUsage) {
232 nativeEnqueuer.onInstantiatedType(type); 223 nativeEnqueuer.onInstantiatedType(type);
233 } 224 }
234 backend.registerInstantiatedType(type); 225 backend.registerInstantiatedType(type);
235 // TODO(johnniwinther): Share this reasoning with [Universe]. 226 // TODO(johnniwinther): Share this reasoning with [Universe].
236 if (!cls.isAbstract || isNative || mirrorUsage) { 227 if (!cls.isAbstract || isNative || mirrorUsage) {
237 processInstantiatedClass(cls); 228 _processInstantiatedClass(cls);
238 } 229 }
239 }); 230 });
240 } 231 }
241 232
242 bool checkNoEnqueuedInvokedInstanceMethods() { 233 bool checkNoEnqueuedInvokedInstanceMethods() {
243 return strategy.checkEnqueuerConsistency(this); 234 return strategy.checkEnqueuerConsistency(this);
244 } 235 }
245 236
246 void processInstantiatedClassMembers(ClassElement cls) { 237 void processInstantiatedClassMembers(ClassElement cls) {
247 strategy.processInstantiatedClass(this, cls); 238 strategy.processInstantiatedClass(this, cls);
248 } 239 }
249 240
250 void processInstantiatedClassMember(ClassElement cls, Element member) { 241 void processInstantiatedClassMember(ClassElement cls, Element member) {
251 assert(invariant(member, member.isDeclaration)); 242 assert(invariant(member, member.isDeclaration));
252 if (isProcessed(member)) return; 243 if (isProcessed(member)) return;
253 if (!member.isInstanceMember) return; 244 if (!member.isInstanceMember) return;
254 String memberName = member.name; 245 String memberName = member.name;
255 246
256 if (member.isField) { 247 if (member.isField) {
257 // The obvious thing to test here would be "member.isNative", 248 // The obvious thing to test here would be "member.isNative",
258 // however, that only works after metadata has been parsed/analyzed, 249 // however, that only works after metadata has been parsed/analyzed,
259 // and that may not have happened yet. 250 // and that may not have happened yet.
260 // So instead we use the enclosing class, which we know have had 251 // So instead we use the enclosing class, which we know have had
261 // its metadata parsed and analyzed. 252 // its metadata parsed and analyzed.
262 // Note: this assumes that there are no non-native fields on native 253 // Note: this assumes that there are no non-native fields on native
263 // classes, which may not be the case when a native class is subclassed. 254 // classes, which may not be the case when a native class is subclassed.
264 if (backend.isNative(cls)) { 255 if (backend.isNative(cls)) {
265 openWorld.registerUsedElement(member); 256 _openWorld.registerUsedElement(member);
266 if (_universe.hasInvokedGetter(member, openWorld) || 257 if (_universe.hasInvokedGetter(member, _openWorld) ||
267 _universe.hasInvocation(member, openWorld)) { 258 _universe.hasInvocation(member, _openWorld)) {
268 addToWorkList(member); 259 _addToWorkList(member);
269 return; 260 return;
270 } 261 }
271 if (_universe.hasInvokedSetter(member, openWorld)) { 262 if (_universe.hasInvokedSetter(member, _openWorld)) {
272 addToWorkList(member); 263 _addToWorkList(member);
273 return; 264 return;
274 } 265 }
275 // Native fields need to go into instanceMembersByName as they 266 // Native fields need to go into instanceMembersByName as they
276 // are virtual instantiation points and escape points. 267 // are virtual instantiation points and escape points.
277 } else { 268 } else {
278 // All field initializers must be resolved as they could 269 // All field initializers must be resolved as they could
279 // have an observable side-effect (and cannot be tree-shaken 270 // have an observable side-effect (and cannot be tree-shaken
280 // away). 271 // away).
281 addToWorkList(member); 272 _addToWorkList(member);
282 return; 273 return;
283 } 274 }
284 } else if (member.isFunction) { 275 } else if (member.isFunction) {
285 FunctionElement function = member; 276 FunctionElement function = member;
286 function.computeType(resolution); 277 function.computeType(_resolution);
287 if (function.name == Identifiers.noSuchMethod_) { 278 if (function.name == Identifiers.noSuchMethod_) {
288 registerNoSuchMethod(function); 279 _registerNoSuchMethod(function);
289 } 280 }
290 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { 281 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) {
291 _registerCallMethodWithFreeTypeVariables(function); 282 _registerCallMethodWithFreeTypeVariables(function);
292 } 283 }
293 // If there is a property access with the same name as a method we 284 // If there is a property access with the same name as a method we
294 // need to emit the method. 285 // need to emit the method.
295 if (_universe.hasInvokedGetter(function, openWorld)) { 286 if (_universe.hasInvokedGetter(function, _openWorld)) {
296 registerClosurizedMember(function); 287 _registerClosurizedMember(function);
297 addToWorkList(function); 288 _addToWorkList(function);
298 return; 289 return;
299 } 290 }
300 // Store the member in [instanceFunctionsByName] to catch 291 // Store the member in [instanceFunctionsByName] to catch
301 // getters on the function. 292 // getters on the function.
302 instanceFunctionsByName 293 _instanceFunctionsByName
303 .putIfAbsent(memberName, () => new Set<Element>()) 294 .putIfAbsent(memberName, () => new Set<Element>())
304 .add(member); 295 .add(member);
305 if (_universe.hasInvocation(function, openWorld)) { 296 if (_universe.hasInvocation(function, _openWorld)) {
306 addToWorkList(function); 297 _addToWorkList(function);
307 return; 298 return;
308 } 299 }
309 } else if (member.isGetter) { 300 } else if (member.isGetter) {
310 FunctionElement getter = member; 301 FunctionElement getter = member;
311 getter.computeType(resolution); 302 getter.computeType(_resolution);
312 if (_universe.hasInvokedGetter(getter, openWorld)) { 303 if (_universe.hasInvokedGetter(getter, _openWorld)) {
313 addToWorkList(getter); 304 _addToWorkList(getter);
314 return; 305 return;
315 } 306 }
316 // We don't know what selectors the returned closure accepts. If 307 // We don't know what selectors the returned closure accepts. If
317 // the set contains any selector we have to assume that it matches. 308 // the set contains any selector we have to assume that it matches.
318 if (_universe.hasInvocation(getter, openWorld)) { 309 if (_universe.hasInvocation(getter, _openWorld)) {
319 addToWorkList(getter); 310 _addToWorkList(getter);
320 return; 311 return;
321 } 312 }
322 } else if (member.isSetter) { 313 } else if (member.isSetter) {
323 FunctionElement setter = member; 314 FunctionElement setter = member;
324 setter.computeType(resolution); 315 setter.computeType(_resolution);
325 if (_universe.hasInvokedSetter(setter, openWorld)) { 316 if (_universe.hasInvokedSetter(setter, _openWorld)) {
326 addToWorkList(setter); 317 _addToWorkList(setter);
327 return; 318 return;
328 } 319 }
329 } 320 }
330 321
331 // The element is not yet used. Add it to the list of instance 322 // The element is not yet used. Add it to the list of instance
332 // members to still be processed. 323 // members to still be processed.
333 instanceMembersByName 324 _instanceMembersByName
334 .putIfAbsent(memberName, () => new Set<Element>()) 325 .putIfAbsent(memberName, () => new Set<Element>())
335 .add(member); 326 .add(member);
336 } 327 }
337 328
338 void processInstantiatedClass(ClassElement cls) { 329 void _processInstantiatedClass(ClassElement cls) {
339 task.measure(() { 330 task.measure(() {
340 if (_processedClasses.contains(cls)) return; 331 if (_processedClasses.contains(cls)) return;
341 // The class must be resolved to compute the set of all 332 // The class must be resolved to compute the set of all
342 // supertypes. 333 // supertypes.
343 cls.ensureResolved(resolution); 334 cls.ensureResolved(_resolution);
344 335
345 void processClass(ClassElement superclass) { 336 void processClass(ClassElement superclass) {
346 if (_processedClasses.contains(superclass)) return; 337 if (_processedClasses.contains(superclass)) return;
347 338
348 _processedClasses.add(superclass); 339 _processedClasses.add(superclass);
349 recentClasses.add(superclass); 340 _recentClasses.add(superclass);
350 superclass.ensureResolved(resolution); 341 superclass.ensureResolved(_resolution);
351 superclass.implementation.forEachMember(processInstantiatedClassMember); 342 superclass.implementation.forEachMember(processInstantiatedClassMember);
352 resolution.ensureClassMembers(superclass); 343 _resolution.ensureClassMembers(superclass);
353 // We only tell the backend once that [superclass] was instantiated, so 344 // We only tell the backend once that [superclass] was instantiated, so
354 // any additional dependencies must be treated as global 345 // any additional dependencies must be treated as global
355 // dependencies. 346 // dependencies.
356 applyImpact( 347 applyImpact(
357 backend.registerInstantiatedClass(superclass, forResolution: true)); 348 backend.registerInstantiatedClass(superclass, forResolution: true));
358 } 349 }
359 350
360 ClassElement superclass = cls; 351 ClassElement superclass = cls;
361 while (superclass != null) { 352 while (superclass != null) {
362 processClass(superclass); 353 processClass(superclass);
363 superclass = superclass.superclass; 354 superclass = superclass.superclass;
364 } 355 }
365 }); 356 });
366 } 357 }
367 358
368 void registerDynamicUse(DynamicUse dynamicUse) { 359 void processDynamicUse(DynamicUse dynamicUse) {
369 task.measure(() { 360 task.measure(() {
370 if (_universe.registerDynamicUse(dynamicUse)) { 361 if (_universe.registerDynamicUse(dynamicUse)) {
371 handleUnseenSelector(dynamicUse); 362 _handleUnseenSelector(dynamicUse);
372 } 363 }
373 }); 364 });
374 } 365 }
375 366
376 void processSet( 367 void _processSet(
377 Map<String, Set<Element>> map, String memberName, bool f(Element e)) { 368 Map<String, Set<Element>> map, String memberName, bool f(Element e)) {
378 Set<Element> members = map[memberName]; 369 Set<Element> members = map[memberName];
379 if (members == null) return; 370 if (members == null) return;
380 // [f] might add elements to [: map[memberName] :] during the loop below 371 // [f] might add elements to [: map[memberName] :] during the loop below
381 // so we create a new list for [: map[memberName] :] and prepend the 372 // so we create a new list for [: map[memberName] :] and prepend the
382 // [remaining] members after the loop. 373 // [remaining] members after the loop.
383 map[memberName] = new Set<Element>(); 374 map[memberName] = new Set<Element>();
384 Set<Element> remaining = new Set<Element>(); 375 Set<Element> remaining = new Set<Element>();
385 for (Element member in members) { 376 for (Element member in members) {
386 if (!f(member)) remaining.add(member); 377 if (!f(member)) remaining.add(member);
387 } 378 }
388 map[memberName].addAll(remaining); 379 map[memberName].addAll(remaining);
389 } 380 }
390 381
391 processInstanceMembers(String n, bool f(Element e)) { 382 void _processInstanceMembers(String n, bool f(Element e)) {
392 processSet(instanceMembersByName, n, f); 383 _processSet(_instanceMembersByName, n, f);
393 } 384 }
394 385
395 processInstanceFunctions(String n, bool f(Element e)) { 386 void _processInstanceFunctions(String n, bool f(Element e)) {
396 processSet(instanceFunctionsByName, n, f); 387 _processSet(_instanceFunctionsByName, n, f);
397 } 388 }
398 389
399 void handleUnseenSelector(DynamicUse universeSelector) { 390 void _handleUnseenSelector(DynamicUse dynamicUse) {
400 strategy.processDynamicUse(this, universeSelector);
401 }
402
403 void handleUnseenSelectorInternal(DynamicUse dynamicUse) {
404 Selector selector = dynamicUse.selector; 391 Selector selector = dynamicUse.selector;
405 String methodName = selector.name; 392 String methodName = selector.name;
406 processInstanceMembers(methodName, (Element member) { 393 _processInstanceMembers(methodName, (Element member) {
407 if (dynamicUse.appliesUnnamed(member, openWorld)) { 394 if (dynamicUse.appliesUnnamed(member, _openWorld)) {
408 if (member.isFunction && selector.isGetter) { 395 if (member.isFunction && selector.isGetter) {
409 registerClosurizedMember(member); 396 _registerClosurizedMember(member);
410 } 397 }
411 addToWorkList(member); 398 _addToWorkList(member);
412 return true; 399 return true;
413 } 400 }
414 return false; 401 return false;
415 }); 402 });
416 if (selector.isGetter) { 403 if (selector.isGetter) {
417 processInstanceFunctions(methodName, (Element member) { 404 _processInstanceFunctions(methodName, (Element member) {
418 if (dynamicUse.appliesUnnamed(member, openWorld)) { 405 if (dynamicUse.appliesUnnamed(member, _openWorld)) {
419 registerClosurizedMember(member); 406 _registerClosurizedMember(member);
420 return true; 407 return true;
421 } 408 }
422 return false; 409 return false;
423 }); 410 });
424 } 411 }
425 } 412 }
426 413
427 /** 414 void processStaticUse(StaticUse staticUse) {
428 * Documentation wanted -- johnniwinther
429 *
430 * Invariant: [element] must be a declaration element.
431 */
432 void registerStaticUse(StaticUse staticUse) {
433 strategy.processStaticUse(this, staticUse);
434 }
435
436 void registerStaticUseInternal(StaticUse staticUse) {
437 Element element = staticUse.element; 415 Element element = staticUse.element;
438 assert(invariant(element, element.isDeclaration, 416 assert(invariant(element, element.isDeclaration,
439 message: "Element ${element} is not the declaration.")); 417 message: "Element ${element} is not the declaration."));
440 _universe.registerStaticUse(staticUse); 418 _universe.registerStaticUse(staticUse);
441 applyImpact(backend.registerStaticUse(element, forResolution: true)); 419 applyImpact(backend.registerStaticUse(element, forResolution: true));
442 bool addElement = true; 420 bool addElement = true;
443 switch (staticUse.kind) { 421 switch (staticUse.kind) {
444 case StaticUseKind.STATIC_TEAR_OFF: 422 case StaticUseKind.STATIC_TEAR_OFF:
445 applyImpact(backend.registerGetOfStaticFunction()); 423 applyImpact(backend.registerGetOfStaticFunction());
446 break; 424 break;
447 case StaticUseKind.FIELD_GET: 425 case StaticUseKind.FIELD_GET:
448 case StaticUseKind.FIELD_SET: 426 case StaticUseKind.FIELD_SET:
449 case StaticUseKind.CLOSURE: 427 case StaticUseKind.CLOSURE:
450 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and 428 // TODO(johnniwinther): Avoid this. Currently [FIELD_GET] and
451 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue. 429 // [FIELD_SET] contains [BoxFieldElement]s which we cannot enqueue.
452 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot 430 // Also [CLOSURE] contains [LocalFunctionElement] which we cannot
453 // enqueue. 431 // enqueue.
454 LocalFunctionElement closure = staticUse.element; 432 LocalFunctionElement closure = staticUse.element;
455 if (closure.type.containsTypeVariables) { 433 if (closure.type.containsTypeVariables) {
456 universe.closuresWithFreeTypeVariables.add(closure); 434 _universe.closuresWithFreeTypeVariables.add(closure);
457 } 435 }
458 addElement = false; 436 addElement = false;
459 break; 437 break;
460 case StaticUseKind.SUPER_FIELD_SET: 438 case StaticUseKind.SUPER_FIELD_SET:
461 case StaticUseKind.SUPER_TEAR_OFF: 439 case StaticUseKind.SUPER_TEAR_OFF:
462 case StaticUseKind.GENERAL: 440 case StaticUseKind.GENERAL:
463 case StaticUseKind.DIRECT_USE: 441 case StaticUseKind.DIRECT_USE:
464 break; 442 break;
465 case StaticUseKind.CONSTRUCTOR_INVOKE: 443 case StaticUseKind.CONSTRUCTOR_INVOKE:
466 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE: 444 case StaticUseKind.CONST_CONSTRUCTOR_INVOKE:
467 _registerInstantiatedType(staticUse.type, 445 _registerInstantiatedType(staticUse.type,
468 constructor: staticUse.element, globalDependency: false); 446 constructor: staticUse.element, globalDependency: false);
469 break; 447 break;
470 case StaticUseKind.REDIRECTION: 448 case StaticUseKind.REDIRECTION:
471 _registerInstantiatedType(staticUse.type, 449 _registerInstantiatedType(staticUse.type,
472 constructor: staticUse.element, 450 constructor: staticUse.element,
473 globalDependency: false, 451 globalDependency: false,
474 isRedirection: true); 452 isRedirection: true);
475 break; 453 break;
476 case StaticUseKind.DIRECT_INVOKE: 454 case StaticUseKind.DIRECT_INVOKE:
477 invariant( 455 invariant(
478 element, 'Direct static use is not supported for resolution.'); 456 element, 'Direct static use is not supported for resolution.');
479 break; 457 break;
480 } 458 }
481 if (addElement) { 459 if (addElement) {
482 addToWorkList(element); 460 _addToWorkList(element);
483 } 461 }
484 } 462 }
485 463
486 void registerTypeUse(TypeUse typeUse) { 464 void processTypeUse(TypeUse typeUse) {
487 strategy.processTypeUse(this, typeUse);
488 }
489
490 void registerTypeUseInternal(TypeUse typeUse) {
491 DartType type = typeUse.type; 465 DartType type = typeUse.type;
492 switch (typeUse.kind) { 466 switch (typeUse.kind) {
493 case TypeUseKind.INSTANTIATION: 467 case TypeUseKind.INSTANTIATION:
494 _registerInstantiatedType(type, globalDependency: false); 468 _registerInstantiatedType(type, globalDependency: false);
495 break; 469 break;
496 case TypeUseKind.MIRROR_INSTANTIATION: 470 case TypeUseKind.MIRROR_INSTANTIATION:
497 _registerInstantiatedType(type, 471 _registerInstantiatedType(type,
498 mirrorUsage: true, globalDependency: false); 472 mirrorUsage: true, globalDependency: false);
499 break; 473 break;
500 case TypeUseKind.NATIVE_INSTANTIATION: 474 case TypeUseKind.NATIVE_INSTANTIATION:
501 _registerInstantiatedType(type, 475 _registerInstantiatedType(type,
502 nativeUsage: true, globalDependency: true); 476 nativeUsage: true, globalDependency: true);
503 break; 477 break;
504 case TypeUseKind.IS_CHECK: 478 case TypeUseKind.IS_CHECK:
505 case TypeUseKind.AS_CAST: 479 case TypeUseKind.AS_CAST:
506 case TypeUseKind.CATCH_TYPE: 480 case TypeUseKind.CATCH_TYPE:
507 _registerIsCheck(type); 481 _registerIsCheck(type);
508 break; 482 break;
509 case TypeUseKind.CHECKED_MODE_CHECK: 483 case TypeUseKind.CHECKED_MODE_CHECK:
510 if (options.enableTypeAssertions) { 484 if (_options.enableTypeAssertions) {
511 _registerIsCheck(type); 485 _registerIsCheck(type);
512 } 486 }
513 break; 487 break;
514 case TypeUseKind.TYPE_LITERAL: 488 case TypeUseKind.TYPE_LITERAL:
515 break; 489 break;
516 } 490 }
517 } 491 }
518 492
519 void _registerIsCheck(DartType type) { 493 void _registerIsCheck(DartType type) {
520 type = _universe.registerIsCheck(type, resolution); 494 type = _universe.registerIsCheck(type, _resolution);
521 // Even in checked mode, type annotations for return type and argument 495 // Even in checked mode, type annotations for return type and argument
522 // types do not imply type checks, so there should never be a check 496 // types do not imply type checks, so there should never be a check
523 // against the type variable of a typedef. 497 // against the type variable of a typedef.
524 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef); 498 assert(!type.isTypeVariable || !type.element.enclosingElement.isTypedef);
525 } 499 }
526 500
527 void _registerCallMethodWithFreeTypeVariables(Element element) { 501 void _registerCallMethodWithFreeTypeVariables(Element element) {
528 applyImpact(backend.registerCallMethodWithFreeTypeVariables(element, 502 applyImpact(backend.registerCallMethodWithFreeTypeVariables(element,
529 forResolution: true)); 503 forResolution: true));
530 _universe.callMethodsWithFreeTypeVariables.add(element); 504 _universe.callMethodsWithFreeTypeVariables.add(element);
531 } 505 }
532 506
533 void registerClosurizedMember(TypedElement element) { 507 void _registerClosurizedMember(TypedElement element) {
534 assert(element.isInstanceMember); 508 assert(element.isInstanceMember);
535 if (element.computeType(resolution).containsTypeVariables) { 509 if (element.computeType(_resolution).containsTypeVariables) {
536 applyImpact(backend.registerClosureWithFreeTypeVariables(element, 510 applyImpact(backend.registerClosureWithFreeTypeVariables(element,
537 forResolution: true)); 511 forResolution: true));
538 _universe.closuresWithFreeTypeVariables.add(element); 512 _universe.closuresWithFreeTypeVariables.add(element);
539 } 513 }
540 applyImpact(backend.registerBoundClosure()); 514 applyImpact(backend.registerBoundClosure());
541 _universe.closurizedMembers.add(element); 515 _universe.closurizedMembers.add(element);
542 } 516 }
543 517
544 void forEach(void f(WorkItem work)) { 518 void forEach(void f(WorkItem work)) {
545 do { 519 do {
546 while (queue.isNotEmpty) { 520 while (_queue.isNotEmpty) {
547 // TODO(johnniwinther): Find an optimal process order. 521 // TODO(johnniwinther): Find an optimal process order.
548 WorkItem work = queue.removeLast(); 522 WorkItem work = _queue.removeLast();
549 if (!isProcessed(work.element)) { 523 if (!isProcessed(work.element)) {
550 strategy.processWorkItem(f, work); 524 strategy.processWorkItem(f, work);
551 registerProcessedElement(work.element); 525 registerProcessedElement(work.element);
552 } 526 }
553 } 527 }
554 List recents = recentClasses.toList(growable: false); 528 List recents = _recentClasses.toList(growable: false);
555 recentClasses.clear(); 529 _recentClasses.clear();
556 if (!onQueueEmpty(recents)) recentClasses.addAll(recents); 530 if (!_onQueueEmpty(recents)) {
557 } while (queue.isNotEmpty || recentClasses.isNotEmpty); 531 _recentClasses.addAll(recents);
532 }
533 } while (_queue.isNotEmpty || _recentClasses.isNotEmpty);
558 } 534 }
559 535
560 void logSummary(log(message)) { 536 void logSummary(log(message)) {
561 log('Resolved ${processedElements.length} elements.'); 537 log('Resolved ${processedElements.length} elements.');
562 nativeEnqueuer.logSummary(log); 538 nativeEnqueuer.logSummary(log);
563 } 539 }
564 540
565 String toString() => 'Enqueuer($name)'; 541 String toString() => 'Enqueuer($name)';
566 542
567 /// All declaration elements that have been processed by the resolver.
568 final Set<AstElement> processedElements;
569
570 Iterable<Entity> get processedEntities => processedElements; 543 Iterable<Entity> get processedEntities => processedElements;
571 544
572 final Queue<ResolutionWorkItem> queue;
573
574 /// Queue of deferred resolution actions to execute when the resolution queue
575 /// has been emptied.
576 final Queue<_DeferredAction> deferredQueue;
577
578 static const ImpactUseCase IMPACT_USE =
579 const ImpactUseCase('ResolutionEnqueuer');
580
581 ImpactUseCase get impactUse => IMPACT_USE; 545 ImpactUseCase get impactUse => IMPACT_USE;
582 546
583 bool get isResolutionQueue => true; 547 bool get isResolutionQueue => true;
584 548
585 bool isProcessed(Element member) => processedElements.contains(member); 549 bool isProcessed(Element member) => processedElements.contains(member);
586 550
587 /// Returns `true` if [element] has been processed by the resolution enqueuer. 551 /// Returns `true` if [element] has been processed by the resolution enqueuer.
588 bool hasBeenProcessed(Element element) { 552 bool hasBeenProcessed(Element element) {
589 return processedElements.contains(element.analyzableElement.declaration); 553 return processedElements.contains(element.analyzableElement.declaration);
590 } 554 }
591 555
592 /// Registers [element] as processed by the resolution enqueuer. 556 /// Registers [element] as processed by the resolution enqueuer.
593 void registerProcessedElement(AstElement element) { 557 void registerProcessedElement(AstElement element) {
594 processedElements.add(element); 558 processedElements.add(element);
595 backend.onElementResolved(element); 559 backend.onElementResolved(element);
596 } 560 }
597 561
598 /** 562 /// Adds [element] to the work list if it has not already been processed.
599 * Adds [element] to the work list if it has not already been processed. 563 ///
600 * 564 /// Invariant: [element] must be a declaration element.
601 * Returns [true] if the element was actually added to the queue. 565 void _addToWorkList(Element element) {
602 */ 566 assert(invariant(element, element.isDeclaration));
603 bool internalAddToWorkList(Element element) { 567 if (element.isMalformed) return;
604 if (element.isMalformed) return false;
605 568
606 assert(invariant(element, element is AnalyzableElement, 569 assert(invariant(element, element is AnalyzableElement,
607 message: 'Element $element is not analyzable.')); 570 message: 'Element $element is not analyzable.'));
608 if (hasBeenProcessed(element)) return false; 571 if (hasBeenProcessed(element)) return;
609 if (queueIsClosed) { 572 if (queueIsClosed) {
610 throw new SpannableAssertionFailure( 573 throw new SpannableAssertionFailure(
611 element, "Resolution work list is closed. Trying to add $element."); 574 element, "Resolution work list is closed. Trying to add $element.");
612 } 575 }
613 576
614 openWorld.registerUsedElement(element); 577 _openWorld.registerUsedElement(element);
615 578
616 ResolutionWorkItem workItem = resolution.createWorkItem(element); 579 ResolutionWorkItem workItem = _resolution.createWorkItem(element);
617 queue.add(workItem); 580 _queue.add(workItem);
618 581
619 // Enable isolate support if we start using something from the isolate 582 // Enable isolate support if we start using something from the isolate
620 // library, or timers for the async library. We exclude constant fields, 583 // library, or timers for the async library. We exclude constant fields,
621 // which are ending here because their initializing expression is compiled. 584 // which are ending here because their initializing expression is compiled.
622 LibraryElement library = element.library; 585 LibraryElement library = element.library;
623 if (!universe.hasIsolateSupport && (!element.isField || !element.isConst)) { 586 if (!universe.hasIsolateSupport && (!element.isField || !element.isConst)) {
624 String uri = library.canonicalUri.toString(); 587 String uri = library.canonicalUri.toString();
625 if (uri == 'dart:isolate') { 588 if (uri == 'dart:isolate') {
626 enableIsolateSupport(); 589 _enableIsolateSupport();
627 } else if (uri == 'dart:async') { 590 } else if (uri == 'dart:async') {
628 if (element.name == '_createTimer' || 591 if (element.name == '_createTimer' ||
629 element.name == '_createPeriodicTimer') { 592 element.name == '_createPeriodicTimer') {
630 // The [:Timer:] class uses the event queue of the isolate 593 // The [:Timer:] class uses the event queue of the isolate
631 // library, so we make sure that event queue is generated. 594 // library, so we make sure that event queue is generated.
632 enableIsolateSupport(); 595 _enableIsolateSupport();
633 } 596 }
634 } 597 }
635 } 598 }
636 599
637 if (element.isGetter && element.name == Identifiers.runtimeType_) { 600 if (element.isGetter && element.name == Identifiers.runtimeType_) {
638 // Enable runtime type support if we discover a getter called runtimeType. 601 // Enable runtime type support if we discover a getter called runtimeType.
639 // We have to enable runtime type before hitting the codegen, so 602 // We have to enable runtime type before hitting the codegen, so
640 // that constructors know whether they need to generate code for 603 // that constructors know whether they need to generate code for
641 // runtime type. 604 // runtime type.
642 _universe.hasRuntimeTypeSupport = true; 605 _universe.hasRuntimeTypeSupport = true;
643 // TODO(ahe): Record precise dependency here. 606 // TODO(ahe): Record precise dependency here.
644 applyImpact(backend.registerRuntimeType()); 607 applyImpact(backend.registerRuntimeType());
645 } else if (commonElements.isFunctionApplyMethod(element)) { 608 } else if (_commonElements.isFunctionApplyMethod(element)) {
646 _universe.hasFunctionApplySupport = true; 609 _universe.hasFunctionApplySupport = true;
647 } 610 }
648
649 return true;
650 } 611 }
651 612
652 void registerNoSuchMethod(Element element) { 613 void _registerNoSuchMethod(Element element) {
653 backend.registerNoSuchMethod(element); 614 backend.registerNoSuchMethod(element);
654 } 615 }
655 616
656 void enableIsolateSupport() { 617 void _enableIsolateSupport() {
657 _universe.hasIsolateSupport = true; 618 _universe.hasIsolateSupport = true;
658 applyImpact(backend.enableIsolateSupport(forResolution: true)); 619 applyImpact(backend.enableIsolateSupport(forResolution: true));
659 } 620 }
660 621
661 /** 622 /**
662 * Adds an action to the deferred task queue. 623 * Adds an action to the deferred task queue.
663 * 624 *
664 * The action is performed the next time the resolution queue has been 625 * The action is performed the next time the resolution queue has been
665 * emptied. 626 * emptied.
666 * 627 *
667 * The queue is processed in FIFO order. 628 * The queue is processed in FIFO order.
668 */ 629 */
669 void addDeferredAction(Element element, void action()) { 630 void addDeferredAction(Element element, void action()) {
670 if (queueIsClosed) { 631 if (queueIsClosed) {
671 throw new SpannableAssertionFailure( 632 throw new SpannableAssertionFailure(
672 element, 633 element,
673 "Resolution work list is closed. " 634 "Resolution work list is closed. "
674 "Trying to add deferred action for $element"); 635 "Trying to add deferred action for $element");
675 } 636 }
676 deferredQueue.add(new _DeferredAction(element, action)); 637 _deferredQueue.add(new _DeferredAction(element, action));
677 } 638 }
678 639
679 /// [onQueueEmpty] is called whenever the queue is drained. [recentClasses] 640 /// [_onQueueEmpty] is called whenever the queue is drained. [recentClasses]
680 /// contains the set of all classes seen for the first time since 641 /// contains the set of all classes seen for the first time since
681 /// [onQueueEmpty] was called last. A return value of [true] indicates that 642 /// [_onQueueEmpty] was called last. A return value of [true] indicates that
682 /// the [recentClasses] have been processed and may be cleared. If [false] is 643 /// the [recentClasses] have been processed and may be cleared. If [false] is
683 /// returned, [onQueueEmpty] will be called once the queue is empty again (or 644 /// returned, [_onQueueEmpty] will be called once the queue is empty again (or
684 /// still empty) and [recentClasses] will be a superset of the current value. 645 /// still empty) and [recentClasses] will be a superset of the current value.
685 bool onQueueEmpty(Iterable<ClassElement> recentClasses) { 646 bool _onQueueEmpty(Iterable<ClassElement> recentClasses) {
686 _emptyDeferredQueue(); 647 _emptyDeferredQueue();
687 648
688 return backend.onQueueEmpty(this, recentClasses); 649 return backend.onQueueEmpty(this, recentClasses);
689 } 650 }
690 651
691 void emptyDeferredQueueForTesting() => _emptyDeferredQueue(); 652 void emptyDeferredQueueForTesting() => _emptyDeferredQueue();
692 653
693 void _emptyDeferredQueue() { 654 void _emptyDeferredQueue() {
694 while (!deferredQueue.isEmpty) { 655 while (!_deferredQueue.isEmpty) {
695 _DeferredAction task = deferredQueue.removeFirst(); 656 _DeferredAction task = _deferredQueue.removeFirst();
696 reporter.withCurrentElement(task.element, task.action); 657 _reporter.withCurrentElement(task.element, task.action);
697 } 658 }
698 } 659 }
699 660
700 void forgetElement(Element element, Compiler compiler) { 661 void forgetElement(Element element, Compiler compiler) {
701 _universe.forgetElement(element, compiler); 662 _universe.forgetElement(element, compiler);
702 _processedClasses.remove(element); 663 _processedClasses.remove(element);
703 instanceMembersByName[element.name]?.remove(element); 664 _instanceMembersByName[element.name]?.remove(element);
704 instanceFunctionsByName[element.name]?.remove(element); 665 _instanceFunctionsByName[element.name]?.remove(element);
705 processedElements.remove(element); 666 processedElements.remove(element);
706 } 667 }
707 } 668 }
708 669
709 void removeFromSet(Map<String, Set<Element>> map, Element element) { 670 void removeFromSet(Map<String, Set<Element>> map, Element element) {
710 Set<Element> set = map[element.name]; 671 Set<Element> set = map[element.name];
711 if (set == null) return; 672 if (set == null) return;
712 set.remove(element); 673 set.remove(element);
713 } 674 }
714 675
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 void processWorkItem(void f(WorkItem work), WorkItem work) { 709 void processWorkItem(void f(WorkItem work), WorkItem work) {
749 f(work); 710 f(work);
750 } 711 }
751 } 712 }
752 713
753 /// Strategy that only enqueues directly used elements. 714 /// Strategy that only enqueues directly used elements.
754 class DirectEnqueuerStrategy extends EnqueuerStrategy { 715 class DirectEnqueuerStrategy extends EnqueuerStrategy {
755 const DirectEnqueuerStrategy(); 716 const DirectEnqueuerStrategy();
756 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) { 717 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {
757 if (staticUse.kind == StaticUseKind.DIRECT_USE) { 718 if (staticUse.kind == StaticUseKind.DIRECT_USE) {
758 enqueuer.registerStaticUseInternal(staticUse); 719 enqueuer.processStaticUse(staticUse);
759 } 720 }
760 } 721 }
761 } 722 }
762 723
763 /// Strategy used for tree-shaking. 724 /// Strategy used for tree-shaking.
764 class TreeShakingEnqueuerStrategy extends EnqueuerStrategy { 725 class TreeShakingEnqueuerStrategy extends EnqueuerStrategy {
765 const TreeShakingEnqueuerStrategy(); 726 const TreeShakingEnqueuerStrategy();
766 727
767 @override 728 @override
768 void processInstantiatedClass(EnqueuerImpl enqueuer, ClassElement cls) { 729 void processInstantiatedClass(EnqueuerImpl enqueuer, ClassElement cls) {
769 cls.implementation.forEachMember(enqueuer.processInstantiatedClassMember); 730 cls.implementation.forEachMember(enqueuer.processInstantiatedClassMember);
770 } 731 }
771 732
772 @override 733 @override
773 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) { 734 void processStaticUse(EnqueuerImpl enqueuer, StaticUse staticUse) {
774 enqueuer.registerStaticUseInternal(staticUse); 735 enqueuer.processStaticUse(staticUse);
775 } 736 }
776 737
777 @override 738 @override
778 void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) { 739 void processTypeUse(EnqueuerImpl enqueuer, TypeUse typeUse) {
779 enqueuer.registerTypeUseInternal(typeUse); 740 enqueuer.processTypeUse(typeUse);
780 } 741 }
781 742
782 @override 743 @override
783 void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) { 744 void processDynamicUse(EnqueuerImpl enqueuer, DynamicUse dynamicUse) {
784 enqueuer.handleUnseenSelectorInternal(dynamicUse); 745 enqueuer.processDynamicUse(dynamicUse);
785 } 746 }
786 } 747 }
787 748
788 class EnqueuerImplImpactVisitor implements WorldImpactVisitor { 749 class EnqueuerImplImpactVisitor implements WorldImpactVisitor {
789 final EnqueuerImpl enqueuer; 750 final EnqueuerImpl enqueuer;
790 751
791 EnqueuerImplImpactVisitor(this.enqueuer); 752 EnqueuerImplImpactVisitor(this.enqueuer);
792 753
793 @override 754 @override
794 void visitDynamicUse(DynamicUse dynamicUse) { 755 void visitDynamicUse(DynamicUse dynamicUse) {
795 enqueuer.registerDynamicUse(dynamicUse); 756 enqueuer.strategy.processDynamicUse(enqueuer, dynamicUse);
796 } 757 }
797 758
798 @override 759 @override
799 void visitStaticUse(StaticUse staticUse) { 760 void visitStaticUse(StaticUse staticUse) {
800 enqueuer.registerStaticUse(staticUse); 761 enqueuer.strategy.processStaticUse(enqueuer, staticUse);
801 } 762 }
802 763
803 @override 764 @override
804 void visitTypeUse(TypeUse typeUse) { 765 void visitTypeUse(TypeUse typeUse) {
805 enqueuer.registerTypeUse(typeUse); 766 enqueuer.strategy.processTypeUse(enqueuer, typeUse);
806 } 767 }
807 } 768 }
808 769
809 typedef void _DeferredActionFunction(); 770 typedef void _DeferredActionFunction();
810 771
811 class _DeferredAction { 772 class _DeferredAction {
812 final Element element; 773 final Element element;
813 final _DeferredActionFunction action; 774 final _DeferredActionFunction action;
814 775
815 _DeferredAction(this.element, this.action); 776 _DeferredAction(this.element, this.action);
816 } 777 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js_backend/enqueuer.dart » ('j') | pkg/compiler/lib/src/js_backend/enqueuer.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698