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 |