| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 import 'dart:collection' show Queue; | 5 import 'dart:collection' show Queue; |
| 6 | 6 |
| 7 import '../common.dart'; | 7 import '../common.dart'; |
| 8 import '../common/backend_api.dart' show ForeignResolver; | 8 import '../common/backend_api.dart' show ForeignResolver; |
| 9 import '../common/registry.dart' show Registry; | 9 import '../common/registry.dart' show Registry; |
| 10 import '../common/resolution.dart' show Resolution; | 10 import '../common/resolution.dart' show Resolution; |
| 11 import '../compiler.dart' show Compiler; | 11 import '../compiler.dart' show Compiler; |
| 12 import '../constants/values.dart'; | 12 import '../constants/values.dart'; |
| 13 import '../core_types.dart' show CoreTypes; | 13 import '../core_types.dart' show CoreTypes; |
| 14 import '../dart_types.dart'; | 14 import '../dart_types.dart'; |
| 15 import '../elements/elements.dart'; | 15 import '../elements/elements.dart'; |
| 16 import '../elements/modelx.dart' show FunctionElementX; | 16 import '../elements/modelx.dart' show FunctionElementX; |
| 17 import '../enqueue.dart' show Enqueuer; | 17 import '../enqueue.dart' show Enqueuer; |
| 18 import '../js_backend/backend_helpers.dart' show BackendHelpers; | 18 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
| 19 import '../js_backend/js_backend.dart'; | 19 import '../js_backend/js_backend.dart'; |
| 20 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; | 20 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; |
| 21 import '../tokens/token.dart' show BeginGroupToken, Token; | 21 import '../tokens/token.dart' show BeginGroupToken, Token; |
| 22 import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN; | 22 import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN; |
| 23 import '../tree/tree.dart'; | 23 import '../tree/tree.dart'; |
| 24 import '../universe/use.dart' show StaticUse, TypeUse; |
| 25 import '../universe/world_impact.dart' show WorldImpactBuilder; |
| 24 import 'behavior.dart'; | 26 import 'behavior.dart'; |
| 25 | 27 |
| 26 /** | 28 /** |
| 27 * This could be an abstract class but we use it as a stub for the dart_backend. | 29 * This could be an abstract class but we use it as a stub for the dart_backend. |
| 28 */ | 30 */ |
| 29 class NativeEnqueuer { | 31 class NativeEnqueuer { |
| 32 /// Called when a [type] has been instantiated natively. |
| 33 void onInstantiatedType(InterfaceType type) {} |
| 34 |
| 30 /// Initial entry point to native enqueuer. | 35 /// Initial entry point to native enqueuer. |
| 31 void processNativeClasses(Iterable<LibraryElement> libraries) {} | 36 void processNativeClasses( |
| 37 WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) {} |
| 32 | 38 |
| 33 /// Registers the [nativeBehavior]. Adds the liveness of its instantiated | 39 /// Registers the [nativeBehavior]. Adds the liveness of its instantiated |
| 34 /// types to the world. | 40 /// types to the world. |
| 35 void registerNativeBehavior(NativeBehavior nativeBehavior, cause) {} | 41 void registerNativeBehavior( |
| 42 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) {} |
| 36 | 43 |
| 37 // TODO(johnniwinther): Move [handleFieldAnnotations] and | 44 // TODO(johnniwinther): Move [handleFieldAnnotations] and |
| 38 // [handleMethodAnnotations] to [JavaScriptBackend] or [NativeData]. | 45 // [handleMethodAnnotations] to [JavaScriptBackend] or [NativeData]. |
| 39 // TODO(johnniwinther): Change the return type to 'bool' and rename them to | 46 // TODO(johnniwinther): Change the return type to 'bool' and rename them to |
| 40 // something like `computeNativeField`. | 47 // something like `computeNativeField`. |
| 41 /// Process the potentially native [field]. Adds information from metadata | 48 /// Process the potentially native [field]. Adds information from metadata |
| 42 /// attributes. | 49 /// attributes. |
| 43 void handleFieldAnnotations(Element field) {} | 50 void handleFieldAnnotations(Element field) {} |
| 44 | 51 |
| 45 /// Process the potentially native [method]. Adds information from metadata | 52 /// Process the potentially native [method]. Adds information from metadata |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 | 86 |
| 80 final Map<ClassElement, Set<ClassElement>> nonNativeSubclasses = | 87 final Map<ClassElement, Set<ClassElement>> nonNativeSubclasses = |
| 81 new Map<ClassElement, Set<ClassElement>>(); | 88 new Map<ClassElement, Set<ClassElement>>(); |
| 82 | 89 |
| 83 /** | 90 /** |
| 84 * Records matched constraints ([SpecialType] or [DartType]). Once a type | 91 * Records matched constraints ([SpecialType] or [DartType]). Once a type |
| 85 * constraint has been matched, there is no need to match it again. | 92 * constraint has been matched, there is no need to match it again. |
| 86 */ | 93 */ |
| 87 final Set matchedTypeConstraints = new Set(); | 94 final Set matchedTypeConstraints = new Set(); |
| 88 | 95 |
| 89 /// Pending actions. Classes in [pendingClasses] have action thunks in | |
| 90 /// [queue] to register the class. | |
| 91 final queue = new Queue(); | |
| 92 bool flushing = false; | |
| 93 | |
| 94 final Enqueuer world; | |
| 95 final Compiler compiler; | 96 final Compiler compiler; |
| 96 final bool enableLiveTypeAnalysis; | 97 final bool enableLiveTypeAnalysis; |
| 97 | 98 |
| 98 ClassElement _annotationCreatesClass; | 99 ClassElement _annotationCreatesClass; |
| 99 ClassElement _annotationReturnsClass; | 100 ClassElement _annotationReturnsClass; |
| 100 ClassElement _annotationJsNameClass; | 101 ClassElement _annotationJsNameClass; |
| 101 | 102 |
| 102 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. | 103 /// Subclasses of [NativeEnqueuerBase] are constructed by the backend. |
| 103 NativeEnqueuerBase(this.world, Compiler compiler, this.enableLiveTypeAnalysis) | 104 NativeEnqueuerBase(Compiler compiler, this.enableLiveTypeAnalysis) |
| 104 : this.compiler = compiler, | 105 : this.compiler = compiler, |
| 105 processedLibraries = compiler.cacheStrategy.newSet(); | 106 processedLibraries = compiler.cacheStrategy.newSet(); |
| 106 | 107 |
| 107 JavaScriptBackend get backend => compiler.backend; | 108 JavaScriptBackend get backend => compiler.backend; |
| 108 BackendHelpers get helpers => backend.helpers; | 109 BackendHelpers get helpers => backend.helpers; |
| 109 Resolution get resolution => compiler.resolution; | 110 Resolution get resolution => compiler.resolution; |
| 110 | 111 |
| 111 DiagnosticReporter get reporter => compiler.reporter; | 112 DiagnosticReporter get reporter => compiler.reporter; |
| 112 CoreTypes get coreTypes => compiler.coreTypes; | 113 CoreTypes get coreTypes => compiler.coreTypes; |
| 113 | 114 |
| 114 void processNativeClasses(Iterable<LibraryElement> libraries) { | 115 void onInstantiatedType(InterfaceType type) { |
| 116 if (unusedClasses.remove(type.element)) { |
| 117 registeredClasses.add(type.element); |
| 118 } |
| 119 } |
| 120 |
| 121 void processNativeClasses( |
| 122 WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) { |
| 115 if (compiler.options.hasIncrementalSupport) { | 123 if (compiler.options.hasIncrementalSupport) { |
| 116 // Since [Set.add] returns bool if an element was added, this restricts | 124 // Since [Set.add] returns bool if an element was added, this restricts |
| 117 // [libraries] to ones that haven't already been processed. This saves | 125 // [libraries] to ones that haven't already been processed. This saves |
| 118 // time during incremental compiles. | 126 // time during incremental compiles. |
| 119 libraries = libraries.where(processedLibraries.add); | 127 libraries = libraries.where(processedLibraries.add); |
| 120 } | 128 } |
| 121 libraries.forEach(processNativeClassesInLibrary); | 129 libraries.forEach(processNativeClassesInLibrary); |
| 122 if (helpers.isolateHelperLibrary != null) { | 130 if (helpers.isolateHelperLibrary != null) { |
| 123 processNativeClassesInLibrary(helpers.isolateHelperLibrary); | 131 processNativeClassesInLibrary(helpers.isolateHelperLibrary); |
| 124 } | 132 } |
| 125 processSubclassesOfNativeClasses(libraries); | 133 processSubclassesOfNativeClasses(libraries); |
| 126 if (!enableLiveTypeAnalysis) { | 134 if (!enableLiveTypeAnalysis) { |
| 127 nativeClasses.forEach((c) => enqueueClass(c, 'forced')); | 135 _registerTypeUses(impactBuilder, nativeClasses, 'forced'); |
| 128 flushQueue(); | |
| 129 } | 136 } |
| 130 } | 137 } |
| 131 | 138 |
| 132 void processNativeClassesInLibrary(LibraryElement library) { | 139 void processNativeClassesInLibrary(LibraryElement library) { |
| 133 // Use implementation to ensure the inclusion of injected members. | 140 // Use implementation to ensure the inclusion of injected members. |
| 134 library.implementation.forEachLocalMember((Element element) { | 141 library.implementation.forEachLocalMember((Element element) { |
| 135 if (element.isClass && backend.isNative(element)) { | 142 if (element.isClass && backend.isNative(element)) { |
| 136 processNativeClass(element); | 143 processNativeClass(element); |
| 137 } | 144 } |
| 138 }); | 145 }); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 if (name == null) { | 333 if (name == null) { |
| 327 name = specString; | 334 name = specString; |
| 328 } else { | 335 } else { |
| 329 reporter.internalError( | 336 reporter.internalError( |
| 330 annotation, 'Too many JSName annotations: ${annotation}'); | 337 annotation, 'Too many JSName annotations: ${annotation}'); |
| 331 } | 338 } |
| 332 } | 339 } |
| 333 return name; | 340 return name; |
| 334 } | 341 } |
| 335 | 342 |
| 336 enqueueClass(ClassElement classElement, cause) { | 343 /// Register [classes] as natively instantiated in [impactBuilder]. |
| 337 assert(unusedClasses.contains(classElement)); | 344 void _registerTypeUses( |
| 338 unusedClasses.remove(classElement); | 345 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { |
| 339 pendingClasses.add(classElement); | 346 for (ClassElement cls in classes) { |
| 340 queue.add(() { | 347 if (!unusedClasses.contains(cls)) { |
| 341 processClass(classElement, cause); | 348 // No need to add [classElement] to [impactBuilder]: it has already been |
| 342 }); | 349 // instantiated and we don't track origins of native instantiations |
| 343 } | 350 // precisely. |
| 344 | 351 continue; |
| 345 void flushQueue() { | 352 } |
| 346 if (flushing) return; | 353 cls.ensureResolved(resolution); |
| 347 flushing = true; | 354 impactBuilder |
| 348 while (!queue.isEmpty) { | 355 .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType)); |
| 349 (queue.removeFirst())(); | |
| 350 } | |
| 351 flushing = false; | |
| 352 } | |
| 353 | |
| 354 processClass(ClassElement classElement, cause) { | |
| 355 // TODO(ahe): Fix this assertion to work in incremental compilation. | |
| 356 assert(compiler.options.hasIncrementalSupport || | |
| 357 !registeredClasses.contains(classElement)); | |
| 358 | |
| 359 bool firstTime = registeredClasses.isEmpty; | |
| 360 pendingClasses.remove(classElement); | |
| 361 registeredClasses.add(classElement); | |
| 362 | |
| 363 // TODO(ahe): Is this really a global dependency? | |
| 364 classElement.ensureResolved(resolution); | |
| 365 compiler.backend.registerInstantiatedType( | |
| 366 classElement.rawType, world, compiler.globalDependencies); | |
| 367 | |
| 368 if (firstTime) { | |
| 369 queue.add(onFirstNativeClass); | |
| 370 } | 356 } |
| 371 } | 357 } |
| 372 | 358 |
| 373 void handleFieldAnnotations(Element element) { | 359 void handleFieldAnnotations(Element element) { |
| 374 if (compiler.serialization.isDeserialized(element)) { | 360 if (compiler.serialization.isDeserialized(element)) { |
| 375 return; | 361 return; |
| 376 } | 362 } |
| 377 if (backend.isNative(element.enclosingElement)) { | 363 if (backend.isNative(element.enclosingElement)) { |
| 378 // Exclude non-instance (static) fields - they not really native and are | 364 // Exclude non-instance (static) fields - they not really native and are |
| 379 // compiled as isolate globals. Access of a property of a constructor | 365 // compiled as isolate globals. Access of a property of a constructor |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 442 Node node = element.parseNode(resolution.parsingContext); | 428 Node node = element.parseNode(resolution.parsingContext); |
| 443 if (node is! FunctionExpression) return false; | 429 if (node is! FunctionExpression) return false; |
| 444 FunctionExpression functionExpression = node; | 430 FunctionExpression functionExpression = node; |
| 445 node = functionExpression.body; | 431 node = functionExpression.body; |
| 446 Token token = node.getBeginToken(); | 432 Token token = node.getBeginToken(); |
| 447 if (identical(token.stringValue, 'native')) return true; | 433 if (identical(token.stringValue, 'native')) return true; |
| 448 return false; | 434 return false; |
| 449 }); | 435 }); |
| 450 } | 436 } |
| 451 | 437 |
| 452 void registerNativeBehavior(NativeBehavior nativeBehavior, cause) { | 438 void registerNativeBehavior( |
| 453 processNativeBehavior(nativeBehavior, cause); | 439 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) { |
| 454 flushQueue(); | 440 _processNativeBehavior(impactBuilder, nativeBehavior, cause); |
| 455 } | 441 } |
| 456 | 442 |
| 457 processNativeBehavior(NativeBehavior behavior, cause) { | 443 void _processNativeBehavior( |
| 458 // TODO(ahe): Is this really a global dependency? | 444 WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) { |
| 459 Registry registry = compiler.globalDependencies; | 445 void registerInstantiation(InterfaceType type) { |
| 460 bool allUsedBefore = unusedClasses.isEmpty; | 446 impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type)); |
| 447 } |
| 448 |
| 449 int unusedBefore = unusedClasses.length; |
| 450 Set<ClassElement> matchingClasses = new Set<ClassElement>(); |
| 461 for (var type in behavior.typesInstantiated) { | 451 for (var type in behavior.typesInstantiated) { |
| 462 if (matchedTypeConstraints.contains(type)) continue; | 452 if (matchedTypeConstraints.contains(type)) continue; |
| 463 matchedTypeConstraints.add(type); | 453 matchedTypeConstraints.add(type); |
| 464 if (type is SpecialType) { | 454 if (type is SpecialType) { |
| 465 if (type == SpecialType.JsObject) { | 455 if (type == SpecialType.JsObject) { |
| 466 backend.registerInstantiatedType( | 456 registerInstantiation(compiler.coreTypes.objectType); |
| 467 compiler.coreTypes.objectType, world, registry); | |
| 468 } | 457 } |
| 469 continue; | 458 continue; |
| 470 } | 459 } |
| 471 if (type is InterfaceType) { | 460 if (type is InterfaceType) { |
| 472 if (type == coreTypes.intType) { | 461 if (type == coreTypes.intType) { |
| 473 backend.registerInstantiatedType(type, world, registry); | 462 registerInstantiation(type); |
| 474 } else if (type == coreTypes.doubleType) { | 463 } else if (type == coreTypes.doubleType) { |
| 475 backend.registerInstantiatedType(type, world, registry); | 464 registerInstantiation(type); |
| 476 } else if (type == coreTypes.numType) { | 465 } else if (type == coreTypes.numType) { |
| 477 backend.registerInstantiatedType( | 466 registerInstantiation(coreTypes.doubleType); |
| 478 coreTypes.doubleType, world, registry); | 467 registerInstantiation(coreTypes.intType); |
| 479 backend.registerInstantiatedType(coreTypes.intType, world, registry); | |
| 480 } else if (type == coreTypes.stringType) { | 468 } else if (type == coreTypes.stringType) { |
| 481 backend.registerInstantiatedType(type, world, registry); | 469 registerInstantiation(type); |
| 482 } else if (type == coreTypes.nullType) { | 470 } else if (type == coreTypes.nullType) { |
| 483 backend.registerInstantiatedType(type, world, registry); | 471 registerInstantiation(type); |
| 484 } else if (type == coreTypes.boolType) { | 472 } else if (type == coreTypes.boolType) { |
| 485 backend.registerInstantiatedType(type, world, registry); | 473 registerInstantiation(type); |
| 486 } else if (compiler.types.isSubtype( | 474 } else if (compiler.types.isSubtype( |
| 487 type, backend.backendClasses.listImplementation.rawType)) { | 475 type, backend.backendClasses.listImplementation.rawType)) { |
| 488 backend.registerInstantiatedType(type, world, registry); | 476 registerInstantiation(type); |
| 489 } | 477 } |
| 490 // TODO(johnniwinther): Improve spec string precision to handle type | 478 // TODO(johnniwinther): Improve spec string precision to handle type |
| 491 // arguments and implements relations that preserve generics. Currently | 479 // arguments and implements relations that preserve generics. Currently |
| 492 // we cannot distinguish between `List`, `List<dynamic>`, and | 480 // we cannot distinguish between `List`, `List<dynamic>`, and |
| 493 // `List<int>` and take all to mean `List<E>`; in effect not including | 481 // `List<int>` and take all to mean `List<E>`; in effect not including |
| 494 // any native subclasses of generic classes. | 482 // any native subclasses of generic classes. |
| 495 // TODO(johnniwinther,sra): Find and replace uses of `List` with the | 483 // TODO(johnniwinther,sra): Find and replace uses of `List` with the |
| 496 // actual implementation classes such as `JSArray` et al. | 484 // actual implementation classes such as `JSArray` et al. |
| 497 enqueueUnusedClassesMatching((ClassElement nativeClass) { | 485 matchingClasses |
| 486 .addAll(_findUnusedClassesMatching((ClassElement nativeClass) { |
| 498 InterfaceType nativeType = nativeClass.thisType; | 487 InterfaceType nativeType = nativeClass.thisType; |
| 499 InterfaceType specType = type.element.thisType; | 488 InterfaceType specType = type.element.thisType; |
| 500 return compiler.types.isSubtype(nativeType, specType); | 489 return compiler.types.isSubtype(nativeType, specType); |
| 501 }, cause, 'subtypeof($type)'); | 490 })); |
| 502 } else if (type.isDynamic) { | 491 } else if (type.isDynamic) { |
| 503 enqueueUnusedClassesMatching((_) => true, cause, 'subtypeof($type)'); | 492 matchingClasses.addAll(unusedClasses); |
| 504 } else { | 493 } else { |
| 505 assert(type is VoidType); | 494 assert(type is VoidType); |
| 506 } | 495 } |
| 507 } | 496 } |
| 497 if (matchingClasses.isNotEmpty && registeredClasses.isEmpty) { |
| 498 matchingClasses.addAll(_onFirstNativeClass(impactBuilder)); |
| 499 } |
| 500 _registerTypeUses(impactBuilder, matchingClasses, cause); |
| 508 | 501 |
| 509 // Give an info so that library developers can compile with -v to find why | 502 // Give an info so that library developers can compile with -v to find why |
| 510 // all the native classes are included. | 503 // all the native classes are included. |
| 511 if (unusedClasses.isEmpty && !allUsedBefore) { | 504 if (unusedBefore == matchingClasses.length) { |
| 512 reporter.log('All native types marked as used due to $cause.'); | 505 reporter.log('All native types marked as used due to $cause.'); |
| 513 } | 506 } |
| 514 } | 507 } |
| 515 | 508 |
| 516 enqueueUnusedClassesMatching(bool predicate(classElement), cause, | 509 Iterable<ClassElement> _findUnusedClassesMatching( |
| 517 [String reason]) { | 510 bool predicate(classElement)) { |
| 518 Iterable matches = unusedClasses.where(predicate); | 511 return unusedClasses.where(predicate); |
| 519 matches.toList().forEach((c) => enqueueClass(c, cause)); | |
| 520 } | 512 } |
| 521 | 513 |
| 522 onFirstNativeClass() { | 514 Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) { |
| 523 staticUse(name) { | 515 void staticUse(name) { |
| 524 backend.enqueue( | 516 Element element = helpers.findHelper(name); |
| 525 world, helpers.findHelper(name), compiler.globalDependencies); | 517 impactBuilder.registerStaticUse(new StaticUse.foreignUse(element)); |
| 518 backend.registerBackendUse(element); |
| 519 compiler.globalDependencies.registerDependency(element); |
| 526 } | 520 } |
| 527 | 521 |
| 528 staticUse('defineProperty'); | 522 staticUse('defineProperty'); |
| 529 staticUse('toStringForNativeObject'); | 523 staticUse('toStringForNativeObject'); |
| 530 staticUse('hashCodeForNativeObject'); | 524 staticUse('hashCodeForNativeObject'); |
| 531 staticUse('convertDartClosureToJS'); | 525 staticUse('convertDartClosureToJS'); |
| 532 addNativeExceptions(); | 526 return _findNativeExceptions(); |
| 533 } | 527 } |
| 534 | 528 |
| 535 addNativeExceptions() { | 529 Iterable<ClassElement> _findNativeExceptions() { |
| 536 enqueueUnusedClassesMatching((classElement) { | 530 return _findUnusedClassesMatching((classElement) { |
| 537 // TODO(sra): Annotate exception classes in dart:html. | 531 // TODO(sra): Annotate exception classes in dart:html. |
| 538 String name = classElement.name; | 532 String name = classElement.name; |
| 539 if (name.contains('Exception')) return true; | 533 if (name.contains('Exception')) return true; |
| 540 if (name.contains('Error')) return true; | 534 if (name.contains('Error')) return true; |
| 541 return false; | 535 return false; |
| 542 }, 'native exception'); | 536 }); |
| 543 } | 537 } |
| 544 } | 538 } |
| 545 | 539 |
| 546 class NativeResolutionEnqueuer extends NativeEnqueuerBase { | 540 class NativeResolutionEnqueuer extends NativeEnqueuerBase { |
| 547 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); | 541 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); |
| 548 | 542 |
| 549 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) | 543 NativeResolutionEnqueuer(Compiler compiler) |
| 550 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); | 544 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
| 551 | 545 |
| 552 void processNativeClass(ClassElement classElement) { | 546 void processNativeClass(ClassElement classElement) { |
| 553 super.processNativeClass(classElement); | 547 super.processNativeClass(classElement); |
| 554 | 548 |
| 555 // Js Interop interfaces do not have tags. | 549 // Js Interop interfaces do not have tags. |
| 556 if (backend.isJsInterop(classElement)) return; | 550 if (backend.isJsInterop(classElement)) return; |
| 557 // Since we map from dispatch tags to classes, a dispatch tag must be used | 551 // Since we map from dispatch tags to classes, a dispatch tag must be used |
| 558 // on only one native class. | 552 // on only one native class. |
| 559 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { | 553 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { |
| 560 ClassElement owner = tagOwner[tag]; | 554 ClassElement owner = tagOwner[tag]; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 return NativeBehavior.ofJsBuiltinCallSend( | 610 return NativeBehavior.ofJsBuiltinCallSend( |
| 617 node, reporter, compiler.coreTypes, resolver); | 611 node, reporter, compiler.coreTypes, resolver); |
| 618 } | 612 } |
| 619 } | 613 } |
| 620 | 614 |
| 621 class NativeCodegenEnqueuer extends NativeEnqueuerBase { | 615 class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
| 622 final CodeEmitterTask emitter; | 616 final CodeEmitterTask emitter; |
| 623 | 617 |
| 624 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); | 618 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); |
| 625 | 619 |
| 626 NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter) | 620 NativeCodegenEnqueuer(Compiler compiler, this.emitter) |
| 627 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); | 621 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
| 628 | 622 |
| 629 void processNativeClasses(Iterable<LibraryElement> libraries) { | 623 void processNativeClasses( |
| 630 super.processNativeClasses(libraries); | 624 WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) { |
| 625 super.processNativeClasses(impactBuilder, libraries); |
| 631 | 626 |
| 632 // HACK HACK - add all the resolved classes. | 627 // HACK HACK - add all the resolved classes. |
| 633 NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; | 628 NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; |
| 629 Set<ClassElement> matchingClasses = new Set<ClassElement>(); |
| 634 for (final classElement in enqueuer.registeredClasses) { | 630 for (final classElement in enqueuer.registeredClasses) { |
| 635 if (unusedClasses.contains(classElement)) { | 631 if (unusedClasses.contains(classElement)) { |
| 636 enqueueClass(classElement, 'was resolved'); | 632 matchingClasses.add(classElement); |
| 637 } | 633 } |
| 638 } | 634 } |
| 639 flushQueue(); | 635 if (matchingClasses.isNotEmpty && registeredClasses.isEmpty) { |
| 636 matchingClasses.addAll(_onFirstNativeClass(impactBuilder)); |
| 637 } |
| 638 _registerTypeUses(impactBuilder, matchingClasses, 'was resolved'); |
| 640 } | 639 } |
| 641 | 640 |
| 642 processClass(ClassElement classElement, cause) { | 641 void _registerTypeUses( |
| 643 super.processClass(classElement, cause); | 642 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { |
| 644 // Add the information that this class is a subtype of its supertypes. The | 643 super._registerTypeUses(impactBuilder, classes, cause); |
| 645 // code emitter and the ssa builder use that information. | 644 |
| 646 addSubtypes(classElement, emitter.nativeEmitter); | 645 for (ClassElement classElement in classes) { |
| 646 // Add the information that this class is a subtype of its supertypes. The |
| 647 // code emitter and the ssa builder use that information. |
| 648 _addSubtypes(classElement, emitter.nativeEmitter); |
| 649 } |
| 647 } | 650 } |
| 648 | 651 |
| 649 void addSubtypes(ClassElement cls, NativeEmitter emitter) { | 652 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { |
| 650 if (!backend.isNative(cls)) return; | 653 if (!backend.isNative(cls)) return; |
| 651 if (doneAddSubtypes.contains(cls)) return; | 654 if (doneAddSubtypes.contains(cls)) return; |
| 652 doneAddSubtypes.add(cls); | 655 doneAddSubtypes.add(cls); |
| 653 | 656 |
| 654 // Walk the superclass chain since classes on the superclass chain might not | 657 // Walk the superclass chain since classes on the superclass chain might not |
| 655 // be instantiated (abstract or simply unused). | 658 // be instantiated (abstract or simply unused). |
| 656 addSubtypes(cls.superclass, emitter); | 659 _addSubtypes(cls.superclass, emitter); |
| 657 | 660 |
| 658 for (DartType type in cls.allSupertypes) { | 661 for (DartType type in cls.allSupertypes) { |
| 659 List<Element> subtypes = | 662 List<Element> subtypes = |
| 660 emitter.subtypes.putIfAbsent(type.element, () => <ClassElement>[]); | 663 emitter.subtypes.putIfAbsent(type.element, () => <ClassElement>[]); |
| 661 subtypes.add(cls); | 664 subtypes.add(cls); |
| 662 } | 665 } |
| 663 | 666 |
| 664 // Skip through all the mixin applications in the super class | 667 // Skip through all the mixin applications in the super class |
| 665 // chain. That way, the direct subtypes set only contain the | 668 // chain. That way, the direct subtypes set only contain the |
| 666 // natives classes. | 669 // natives classes. |
| 667 ClassElement superclass = cls.superclass; | 670 ClassElement superclass = cls.superclass; |
| 668 while (superclass != null && superclass.isMixinApplication) { | 671 while (superclass != null && superclass.isMixinApplication) { |
| 669 assert(!backend.isNative(superclass)); | 672 assert(!backend.isNative(superclass)); |
| 670 superclass = superclass.superclass; | 673 superclass = superclass.superclass; |
| 671 } | 674 } |
| 672 | 675 |
| 673 List<Element> directSubtypes = | 676 List<Element> directSubtypes = |
| 674 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassElement>[]); | 677 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassElement>[]); |
| 675 directSubtypes.add(cls); | 678 directSubtypes.add(cls); |
| 676 } | 679 } |
| 677 | 680 |
| 678 void logSummary(log(message)) { | 681 void logSummary(log(message)) { |
| 679 log('Compiled ${registeredClasses.length} native classes, ' | 682 log('Compiled ${registeredClasses.length} native classes, ' |
| 680 '${unusedClasses.length} native classes omitted.'); | 683 '${unusedClasses.length} native classes omitted.'); |
| 681 } | 684 } |
| 682 } | 685 } |
| OLD | NEW |