| 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.enqueue; | 5 library dart2js.enqueue; |
| 6 | 6 |
| 7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
| 8 | 8 |
| 9 import 'common/names.dart' show Identifiers; | 9 import 'common/names.dart' show Identifiers; |
| 10 import 'common/resolution.dart' show Resolution; | 10 import 'common/resolution.dart' show Resolution; |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 220 | 220 |
| 221 if (member.isField) { | 221 if (member.isField) { |
| 222 // The obvious thing to test here would be "member.isNative", | 222 // The obvious thing to test here would be "member.isNative", |
| 223 // however, that only works after metadata has been parsed/analyzed, | 223 // however, that only works after metadata has been parsed/analyzed, |
| 224 // and that may not have happened yet. | 224 // and that may not have happened yet. |
| 225 // So instead we use the enclosing class, which we know have had | 225 // So instead we use the enclosing class, which we know have had |
| 226 // its metadata parsed and analyzed. | 226 // its metadata parsed and analyzed. |
| 227 // Note: this assumes that there are no non-native fields on native | 227 // Note: this assumes that there are no non-native fields on native |
| 228 // classes, which may not be the case when a native class is subclassed. | 228 // classes, which may not be the case when a native class is subclassed. |
| 229 if (compiler.backend.isNative(cls)) { | 229 if (compiler.backend.isNative(cls)) { |
| 230 compiler.world.registerUsedElement(member); | 230 compiler.openWorld.registerUsedElement(member); |
| 231 if (universe.hasInvokedGetter(member, compiler.world) || | 231 if (universe.hasInvokedGetter(member, compiler.openWorld) || |
| 232 universe.hasInvocation(member, compiler.world)) { | 232 universe.hasInvocation(member, compiler.openWorld)) { |
| 233 addToWorkList(member); | 233 addToWorkList(member); |
| 234 return; | 234 return; |
| 235 } | 235 } |
| 236 if (universe.hasInvokedSetter(member, compiler.world)) { | 236 if (universe.hasInvokedSetter(member, compiler.openWorld)) { |
| 237 addToWorkList(member); | 237 addToWorkList(member); |
| 238 return; | 238 return; |
| 239 } | 239 } |
| 240 // Native fields need to go into instanceMembersByName as they | 240 // Native fields need to go into instanceMembersByName as they |
| 241 // are virtual instantiation points and escape points. | 241 // are virtual instantiation points and escape points. |
| 242 } else { | 242 } else { |
| 243 // All field initializers must be resolved as they could | 243 // All field initializers must be resolved as they could |
| 244 // have an observable side-effect (and cannot be tree-shaken | 244 // have an observable side-effect (and cannot be tree-shaken |
| 245 // away). | 245 // away). |
| 246 addToWorkList(member); | 246 addToWorkList(member); |
| 247 return; | 247 return; |
| 248 } | 248 } |
| 249 } else if (member.isFunction) { | 249 } else if (member.isFunction) { |
| 250 FunctionElement function = member; | 250 FunctionElement function = member; |
| 251 function.computeType(resolution); | 251 function.computeType(resolution); |
| 252 if (function.name == Identifiers.noSuchMethod_) { | 252 if (function.name == Identifiers.noSuchMethod_) { |
| 253 registerNoSuchMethod(function); | 253 registerNoSuchMethod(function); |
| 254 } | 254 } |
| 255 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { | 255 if (function.name == Identifiers.call && !cls.typeVariables.isEmpty) { |
| 256 registerCallMethodWithFreeTypeVariables(function); | 256 registerCallMethodWithFreeTypeVariables(function); |
| 257 } | 257 } |
| 258 // If there is a property access with the same name as a method we | 258 // If there is a property access with the same name as a method we |
| 259 // need to emit the method. | 259 // need to emit the method. |
| 260 if (universe.hasInvokedGetter(function, compiler.world)) { | 260 if (universe.hasInvokedGetter(function, compiler.openWorld)) { |
| 261 registerClosurizedMember(function); | 261 registerClosurizedMember(function); |
| 262 addToWorkList(function); | 262 addToWorkList(function); |
| 263 return; | 263 return; |
| 264 } | 264 } |
| 265 // Store the member in [instanceFunctionsByName] to catch | 265 // Store the member in [instanceFunctionsByName] to catch |
| 266 // getters on the function. | 266 // getters on the function. |
| 267 instanceFunctionsByName | 267 instanceFunctionsByName |
| 268 .putIfAbsent(memberName, () => new Set<Element>()) | 268 .putIfAbsent(memberName, () => new Set<Element>()) |
| 269 .add(member); | 269 .add(member); |
| 270 if (universe.hasInvocation(function, compiler.world)) { | 270 if (universe.hasInvocation(function, compiler.openWorld)) { |
| 271 addToWorkList(function); | 271 addToWorkList(function); |
| 272 return; | 272 return; |
| 273 } | 273 } |
| 274 } else if (member.isGetter) { | 274 } else if (member.isGetter) { |
| 275 FunctionElement getter = member; | 275 FunctionElement getter = member; |
| 276 getter.computeType(resolution); | 276 getter.computeType(resolution); |
| 277 if (universe.hasInvokedGetter(getter, compiler.world)) { | 277 if (universe.hasInvokedGetter(getter, compiler.openWorld)) { |
| 278 addToWorkList(getter); | 278 addToWorkList(getter); |
| 279 return; | 279 return; |
| 280 } | 280 } |
| 281 // We don't know what selectors the returned closure accepts. If | 281 // We don't know what selectors the returned closure accepts. If |
| 282 // the set contains any selector we have to assume that it matches. | 282 // the set contains any selector we have to assume that it matches. |
| 283 if (universe.hasInvocation(getter, compiler.world)) { | 283 if (universe.hasInvocation(getter, compiler.openWorld)) { |
| 284 addToWorkList(getter); | 284 addToWorkList(getter); |
| 285 return; | 285 return; |
| 286 } | 286 } |
| 287 } else if (member.isSetter) { | 287 } else if (member.isSetter) { |
| 288 FunctionElement setter = member; | 288 FunctionElement setter = member; |
| 289 setter.computeType(resolution); | 289 setter.computeType(resolution); |
| 290 if (universe.hasInvokedSetter(setter, compiler.world)) { | 290 if (universe.hasInvokedSetter(setter, compiler.openWorld)) { |
| 291 addToWorkList(setter); | 291 addToWorkList(setter); |
| 292 return; | 292 return; |
| 293 } | 293 } |
| 294 } | 294 } |
| 295 | 295 |
| 296 // The element is not yet used. Add it to the list of instance | 296 // The element is not yet used. Add it to the list of instance |
| 297 // members to still be processed. | 297 // members to still be processed. |
| 298 instanceMembersByName | 298 instanceMembersByName |
| 299 .putIfAbsent(memberName, () => new Set<Element>()) | 299 .putIfAbsent(memberName, () => new Set<Element>()) |
| 300 .add(member); | 300 .add(member); |
| 301 } | 301 } |
| 302 | 302 |
| 303 void processInstantiatedClass(ClassElement cls) { | 303 void processInstantiatedClass(ClassElement cls) { |
| 304 task.measure(() { | 304 task.measure(() { |
| 305 if (_processedClasses.contains(cls)) return; | 305 if (_processedClasses.contains(cls)) return; |
| 306 // The class must be resolved to compute the set of all | 306 // The class must be resolved to compute the set of all |
| 307 // supertypes. | 307 // supertypes. |
| 308 cls.ensureResolved(resolution); | 308 cls.ensureResolved(resolution); |
| 309 | 309 |
| 310 void processClass(ClassElement superclass) { | 310 void processClass(ClassElement superclass) { |
| 311 if (_processedClasses.contains(superclass)) return; | 311 if (_processedClasses.contains(superclass)) return; |
| 312 // TODO(johnniwinther): Re-insert this invariant when unittests don't | |
| 313 // fail. There is already a similar invariant on the members. | |
| 314 /*if (!isResolutionQueue) { | |
| 315 assert(invariant(superclass, | |
| 316 superclass.isClosure || | |
| 317 compiler.enqueuer.resolution.isClassProcessed(superclass), | |
| 318 message: "Class $superclass has not been " | |
| 319 "processed in resolution.")); | |
| 320 }*/ | |
| 321 | 312 |
| 322 _processedClasses.add(superclass); | 313 _processedClasses.add(superclass); |
| 323 recentClasses.add(superclass); | 314 recentClasses.add(superclass); |
| 324 superclass.ensureResolved(resolution); | 315 superclass.ensureResolved(resolution); |
| 325 superclass.implementation.forEachMember(processInstantiatedClassMember); | 316 superclass.implementation.forEachMember(processInstantiatedClassMember); |
| 326 if (isResolutionQueue && | 317 if (!compiler.serialization.isDeserialized(superclass)) { |
| 327 !compiler.serialization.isDeserialized(superclass)) { | |
| 328 compiler.resolver.checkClass(superclass); | 318 compiler.resolver.checkClass(superclass); |
| 329 } | 319 } |
| 330 // We only tell the backend once that [superclass] was instantiated, so | 320 // We only tell the backend once that [superclass] was instantiated, so |
| 331 // any additional dependencies must be treated as global | 321 // any additional dependencies must be treated as global |
| 332 // dependencies. | 322 // dependencies. |
| 333 compiler.backend.registerInstantiatedClass( | 323 compiler.backend.registerInstantiatedClass( |
| 334 superclass, this, compiler.globalDependencies); | 324 superclass, this, compiler.globalDependencies); |
| 335 } | 325 } |
| 336 | 326 |
| 337 ClassElement superclass = cls; | 327 ClassElement superclass = cls; |
| 338 while (superclass != null) { | 328 while (superclass != null) { |
| 339 processClass(superclass); | 329 processClass(superclass); |
| 340 superclass = superclass.superclass; | 330 superclass = superclass.superclass; |
| 341 } | 331 } |
| 342 }); | 332 }); |
| 343 } | 333 } |
| 344 | 334 |
| 345 void registerDynamicUse(DynamicUse dynamicUse) { | 335 void registerDynamicUse(DynamicUse dynamicUse) { |
| 346 task.measure(() { | 336 task.measure(() { |
| 347 if (universe.registerDynamicUse(dynamicUse)) { | 337 if (universe.registerDynamicUse(dynamicUse)) { |
| 348 handleUnseenSelector(dynamicUse); | 338 handleUnseenSelector(dynamicUse); |
| 349 } | 339 } |
| 350 }); | 340 }); |
| 351 } | 341 } |
| 352 | 342 |
| 353 void logEnqueueReflectiveAction(action, [msg = ""]) { | 343 void logEnqueueReflectiveAction(action, [msg = ""]) { |
| 354 if (TRACE_MIRROR_ENQUEUING) { | 344 if (TRACE_MIRROR_ENQUEUING) { |
| 355 print("MIRROR_ENQUEUE (${isResolutionQueue ? "R" : "C"}): $action $msg"); | 345 print("MIRROR_ENQUEUE (R): $action $msg"); |
| 356 } | 346 } |
| 357 } | 347 } |
| 358 | 348 |
| 359 /// Enqeue the constructor [ctor] if it is required for reflection. | 349 /// Enqeue the constructor [ctor] if it is required for reflection. |
| 360 /// | 350 /// |
| 361 /// [enclosingWasIncluded] provides a hint whether the enclosing element was | 351 /// [enclosingWasIncluded] provides a hint whether the enclosing element was |
| 362 /// needed for reflection. | 352 /// needed for reflection. |
| 363 void enqueueReflectiveConstructor( | 353 void enqueueReflectiveConstructor( |
| 364 ConstructorElement ctor, bool enclosingWasIncluded) { | 354 ConstructorElement ctor, bool enclosingWasIncluded) { |
| 365 if (shouldIncludeElementDueToMirrors(ctor, | 355 if (shouldIncludeElementDueToMirrors(ctor, |
| (...skipping 11 matching lines...) Expand all Loading... |
| 377 /// | 367 /// |
| 378 /// [enclosingWasIncluded] provides a hint whether the enclosing element was | 368 /// [enclosingWasIncluded] provides a hint whether the enclosing element was |
| 379 /// needed for reflection. | 369 /// needed for reflection. |
| 380 void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) { | 370 void enqueueReflectiveMember(Element element, bool enclosingWasIncluded) { |
| 381 if (shouldIncludeElementDueToMirrors(element, | 371 if (shouldIncludeElementDueToMirrors(element, |
| 382 includedEnclosing: enclosingWasIncluded)) { | 372 includedEnclosing: enclosingWasIncluded)) { |
| 383 logEnqueueReflectiveAction(element); | 373 logEnqueueReflectiveAction(element); |
| 384 if (element.isTypedef) { | 374 if (element.isTypedef) { |
| 385 TypedefElement typedef = element; | 375 TypedefElement typedef = element; |
| 386 typedef.ensureResolved(resolution); | 376 typedef.ensureResolved(resolution); |
| 387 compiler.world.allTypedefs.add(element); | |
| 388 } else if (Elements.isStaticOrTopLevel(element)) { | 377 } else if (Elements.isStaticOrTopLevel(element)) { |
| 389 registerStaticUse(new StaticUse.foreignUse(element.declaration)); | 378 registerStaticUse(new StaticUse.foreignUse(element.declaration)); |
| 390 } else if (element.isInstanceMember) { | 379 } else if (element.isInstanceMember) { |
| 391 // We need to enqueue all members matching this one in subclasses, as | 380 // We need to enqueue all members matching this one in subclasses, as |
| 392 // well. | 381 // well. |
| 393 // TODO(herhut): Use TypedSelector.subtype for enqueueing | 382 // TODO(herhut): Use TypedSelector.subtype for enqueueing |
| 394 DynamicUse dynamicUse = | 383 DynamicUse dynamicUse = |
| 395 new DynamicUse(new Selector.fromElement(element), null); | 384 new DynamicUse(new Selector.fromElement(element), null); |
| 396 registerDynamicUse(dynamicUse); | 385 registerDynamicUse(dynamicUse); |
| 397 if (element.isField) { | 386 if (element.isField) { |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 541 } | 530 } |
| 542 | 531 |
| 543 void handleUnseenSelector(DynamicUse universeSelector) { | 532 void handleUnseenSelector(DynamicUse universeSelector) { |
| 544 strategy.processDynamicUse(this, universeSelector); | 533 strategy.processDynamicUse(this, universeSelector); |
| 545 } | 534 } |
| 546 | 535 |
| 547 void handleUnseenSelectorInternal(DynamicUse dynamicUse) { | 536 void handleUnseenSelectorInternal(DynamicUse dynamicUse) { |
| 548 Selector selector = dynamicUse.selector; | 537 Selector selector = dynamicUse.selector; |
| 549 String methodName = selector.name; | 538 String methodName = selector.name; |
| 550 processInstanceMembers(methodName, (Element member) { | 539 processInstanceMembers(methodName, (Element member) { |
| 551 if (dynamicUse.appliesUnnamed(member, compiler.world)) { | 540 if (dynamicUse.appliesUnnamed(member, compiler.openWorld)) { |
| 552 if (member.isFunction && selector.isGetter) { | 541 if (member.isFunction && selector.isGetter) { |
| 553 registerClosurizedMember(member); | 542 registerClosurizedMember(member); |
| 554 } | 543 } |
| 555 addToWorkList(member); | 544 addToWorkList(member); |
| 556 return true; | 545 return true; |
| 557 } | 546 } |
| 558 return false; | 547 return false; |
| 559 }); | 548 }); |
| 560 if (selector.isGetter) { | 549 if (selector.isGetter) { |
| 561 processInstanceFunctions(methodName, (Element member) { | 550 processInstanceFunctions(methodName, (Element member) { |
| 562 if (dynamicUse.appliesUnnamed(member, compiler.world)) { | 551 if (dynamicUse.appliesUnnamed(member, compiler.openWorld)) { |
| 563 registerClosurizedMember(member); | 552 registerClosurizedMember(member); |
| 564 return true; | 553 return true; |
| 565 } | 554 } |
| 566 return false; | 555 return false; |
| 567 }); | 556 }); |
| 568 } | 557 } |
| 569 } | 558 } |
| 570 | 559 |
| 571 /** | 560 /** |
| 572 * Documentation wanted -- johnniwinther | 561 * Documentation wanted -- johnniwinther |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 726 if (element.isMalformed) return false; | 715 if (element.isMalformed) return false; |
| 727 | 716 |
| 728 assert(invariant(element, element is AnalyzableElement, | 717 assert(invariant(element, element is AnalyzableElement, |
| 729 message: 'Element $element is not analyzable.')); | 718 message: 'Element $element is not analyzable.')); |
| 730 if (hasBeenProcessed(element)) return false; | 719 if (hasBeenProcessed(element)) return false; |
| 731 if (queueIsClosed) { | 720 if (queueIsClosed) { |
| 732 throw new SpannableAssertionFailure( | 721 throw new SpannableAssertionFailure( |
| 733 element, "Resolution work list is closed. Trying to add $element."); | 722 element, "Resolution work list is closed. Trying to add $element."); |
| 734 } | 723 } |
| 735 | 724 |
| 736 compiler.world.registerUsedElement(element); | 725 compiler.openWorld.registerUsedElement(element); |
| 737 | 726 |
| 738 ResolutionWorkItem workItem = compiler.resolution.createWorkItem(element); | 727 ResolutionWorkItem workItem = compiler.resolution.createWorkItem(element); |
| 739 queue.add(workItem); | 728 queue.add(workItem); |
| 740 | 729 |
| 741 // Enable isolate support if we start using something from the isolate | 730 // Enable isolate support if we start using something from the isolate |
| 742 // library, or timers for the async library. We exclude constant fields, | 731 // library, or timers for the async library. We exclude constant fields, |
| 743 // which are ending here because their initializing expression is compiled. | 732 // which are ending here because their initializing expression is compiled. |
| 744 LibraryElement library = element.library; | 733 LibraryElement library = element.library; |
| 745 if (!compiler.hasIsolateSupport && (!element.isField || !element.isConst)) { | 734 if (!compiler.hasIsolateSupport && (!element.isField || !element.isConst)) { |
| 746 String uri = library.canonicalUri.toString(); | 735 String uri = library.canonicalUri.toString(); |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 } | 901 } |
| 913 | 902 |
| 914 typedef void _DeferredActionFunction(); | 903 typedef void _DeferredActionFunction(); |
| 915 | 904 |
| 916 class _DeferredAction { | 905 class _DeferredAction { |
| 917 final Element element; | 906 final Element element; |
| 918 final _DeferredActionFunction action; | 907 final _DeferredActionFunction action; |
| 919 | 908 |
| 920 _DeferredAction(this.element, this.action); | 909 _DeferredAction(this.element, this.action); |
| 921 } | 910 } |
| OLD | NEW |