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 bool maybeFirstTime = registeredClasses.isEmpty; |
Harry Terkelsen
2016/11/11 21:24:27
is this used anywhere?
Johnni Winther
2016/11/14 09:08:36
No.
| |
340 queue.add(() { | 347 for (ClassElement cls in classes) { |
341 processClass(classElement, cause); | 348 if (!unusedClasses.contains(cls)) { |
342 }); | 349 // No need to add [classElement] to [impactBuilder]: it has already been |
343 } | 350 // instantiated and we don't track origins of native instantiations |
344 | 351 // precisely. |
345 void flushQueue() { | 352 continue; |
346 if (flushing) return; | 353 } |
347 flushing = true; | 354 cls.ensureResolved(resolution); |
348 while (!queue.isEmpty) { | 355 impactBuilder |
349 (queue.removeFirst())(); | 356 .registerTypeUse(new TypeUse.nativeInstantiation(cls.rawType)); |
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 } | 357 } |
371 } | 358 } |
372 | 359 |
373 void handleFieldAnnotations(Element element) { | 360 void handleFieldAnnotations(Element element) { |
374 if (compiler.serialization.isDeserialized(element)) { | 361 if (compiler.serialization.isDeserialized(element)) { |
375 return; | 362 return; |
376 } | 363 } |
377 if (backend.isNative(element.enclosingElement)) { | 364 if (backend.isNative(element.enclosingElement)) { |
378 // Exclude non-instance (static) fields - they not really native and are | 365 // Exclude non-instance (static) fields - they not really native and are |
379 // compiled as isolate globals. Access of a property of a constructor | 366 // 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); | 429 Node node = element.parseNode(resolution.parsingContext); |
443 if (node is! FunctionExpression) return false; | 430 if (node is! FunctionExpression) return false; |
444 FunctionExpression functionExpression = node; | 431 FunctionExpression functionExpression = node; |
445 node = functionExpression.body; | 432 node = functionExpression.body; |
446 Token token = node.getBeginToken(); | 433 Token token = node.getBeginToken(); |
447 if (identical(token.stringValue, 'native')) return true; | 434 if (identical(token.stringValue, 'native')) return true; |
448 return false; | 435 return false; |
449 }); | 436 }); |
450 } | 437 } |
451 | 438 |
452 void registerNativeBehavior(NativeBehavior nativeBehavior, cause) { | 439 void registerNativeBehavior( |
453 processNativeBehavior(nativeBehavior, cause); | 440 WorldImpactBuilder impactBuilder, NativeBehavior nativeBehavior, cause) { |
454 flushQueue(); | 441 _processNativeBehavior(impactBuilder, nativeBehavior, cause); |
455 } | 442 } |
456 | 443 |
457 processNativeBehavior(NativeBehavior behavior, cause) { | 444 void _processNativeBehavior( |
458 // TODO(ahe): Is this really a global dependency? | 445 WorldImpactBuilder impactBuilder, NativeBehavior behavior, cause) { |
459 Registry registry = compiler.globalDependencies; | 446 void instantiated(InterfaceType type) { |
460 bool allUsedBefore = unusedClasses.isEmpty; | 447 impactBuilder.registerTypeUse(new TypeUse.nativeInstantiation(type)); |
448 } | |
449 | |
450 int unusedBefore = unusedClasses.length; | |
451 Set<ClassElement> matchingClasses = new Set<ClassElement>(); | |
461 for (var type in behavior.typesInstantiated) { | 452 for (var type in behavior.typesInstantiated) { |
462 if (matchedTypeConstraints.contains(type)) continue; | 453 if (matchedTypeConstraints.contains(type)) continue; |
463 matchedTypeConstraints.add(type); | 454 matchedTypeConstraints.add(type); |
464 if (type is SpecialType) { | 455 if (type is SpecialType) { |
465 if (type == SpecialType.JsObject) { | 456 if (type == SpecialType.JsObject) { |
466 backend.registerInstantiatedType( | 457 instantiated(compiler.coreTypes.objectType); |
467 compiler.coreTypes.objectType, world, registry); | |
468 } | 458 } |
469 continue; | 459 continue; |
470 } | 460 } |
471 if (type is InterfaceType) { | 461 if (type is InterfaceType) { |
472 if (type == coreTypes.intType) { | 462 if (type == coreTypes.intType) { |
473 backend.registerInstantiatedType(type, world, registry); | 463 instantiated(type); |
474 } else if (type == coreTypes.doubleType) { | 464 } else if (type == coreTypes.doubleType) { |
475 backend.registerInstantiatedType(type, world, registry); | 465 instantiated(type); |
476 } else if (type == coreTypes.numType) { | 466 } else if (type == coreTypes.numType) { |
477 backend.registerInstantiatedType( | 467 instantiated(coreTypes.doubleType); |
478 coreTypes.doubleType, world, registry); | 468 instantiated(coreTypes.doubleType); |
Harry Terkelsen
2016/11/11 21:24:27
doubleType -> intType
Johnni Winther
2016/11/14 09:08:36
Good catch!
| |
479 backend.registerInstantiatedType(coreTypes.intType, world, registry); | |
480 } else if (type == coreTypes.stringType) { | 469 } else if (type == coreTypes.stringType) { |
481 backend.registerInstantiatedType(type, world, registry); | 470 instantiated(type); |
482 } else if (type == coreTypes.nullType) { | 471 } else if (type == coreTypes.nullType) { |
483 backend.registerInstantiatedType(type, world, registry); | 472 instantiated(type); |
484 } else if (type == coreTypes.boolType) { | 473 } else if (type == coreTypes.boolType) { |
485 backend.registerInstantiatedType(type, world, registry); | 474 instantiated(type); |
486 } else if (compiler.types.isSubtype( | 475 } else if (compiler.types.isSubtype( |
487 type, backend.backendClasses.listImplementation.rawType)) { | 476 type, backend.backendClasses.listImplementation.rawType)) { |
488 backend.registerInstantiatedType(type, world, registry); | 477 instantiated(type); |
489 } | 478 } |
490 // TODO(johnniwinther): Improve spec string precision to handle type | 479 // TODO(johnniwinther): Improve spec string precision to handle type |
491 // arguments and implements relations that preserve generics. Currently | 480 // arguments and implements relations that preserve generics. Currently |
492 // we cannot distinguish between `List`, `List<dynamic>`, and | 481 // we cannot distinguish between `List`, `List<dynamic>`, and |
493 // `List<int>` and take all to mean `List<E>`; in effect not including | 482 // `List<int>` and take all to mean `List<E>`; in effect not including |
494 // any native subclasses of generic classes. | 483 // any native subclasses of generic classes. |
495 // TODO(johnniwinther,sra): Find and replace uses of `List` with the | 484 // TODO(johnniwinther,sra): Find and replace uses of `List` with the |
496 // actual implementation classes such as `JSArray` et al. | 485 // actual implementation classes such as `JSArray` et al. |
497 enqueueUnusedClassesMatching((ClassElement nativeClass) { | 486 matchingClasses |
487 .addAll(_findUnusedClassesMatching((ClassElement nativeClass) { | |
498 InterfaceType nativeType = nativeClass.thisType; | 488 InterfaceType nativeType = nativeClass.thisType; |
499 InterfaceType specType = type.element.thisType; | 489 InterfaceType specType = type.element.thisType; |
500 return compiler.types.isSubtype(nativeType, specType); | 490 return compiler.types.isSubtype(nativeType, specType); |
501 }, cause, 'subtypeof($type)'); | 491 })); |
502 } else if (type.isDynamic) { | 492 } else if (type.isDynamic) { |
503 enqueueUnusedClassesMatching((_) => true, cause, 'subtypeof($type)'); | 493 matchingClasses.addAll(unusedClasses); |
504 } else { | 494 } else { |
505 assert(type is VoidType); | 495 assert(type is VoidType); |
506 } | 496 } |
507 } | 497 } |
498 if (matchingClasses.isNotEmpty && registeredClasses.isEmpty) { | |
499 matchingClasses.addAll(_onFirstNativeClass(impactBuilder)); | |
500 } | |
501 _registerTypeUses(impactBuilder, matchingClasses, cause); | |
508 | 502 |
509 // Give an info so that library developers can compile with -v to find why | 503 // Give an info so that library developers can compile with -v to find why |
510 // all the native classes are included. | 504 // all the native classes are included. |
511 if (unusedClasses.isEmpty && !allUsedBefore) { | 505 if (unusedBefore == matchingClasses.length) { |
512 reporter.log('All native types marked as used due to $cause.'); | 506 reporter.log('All native types marked as used due to $cause.'); |
513 } | 507 } |
514 } | 508 } |
515 | 509 |
516 enqueueUnusedClassesMatching(bool predicate(classElement), cause, | 510 Iterable<ClassElement> _findUnusedClassesMatching( |
517 [String reason]) { | 511 bool predicate(classElement)) { |
518 Iterable matches = unusedClasses.where(predicate); | 512 return unusedClasses.where(predicate); |
519 matches.toList().forEach((c) => enqueueClass(c, cause)); | |
520 } | 513 } |
521 | 514 |
522 onFirstNativeClass() { | 515 Iterable<ClassElement> _onFirstNativeClass(WorldImpactBuilder impactBuilder) { |
523 staticUse(name) { | 516 void staticUse(name) { |
524 backend.enqueue( | 517 Element element = helpers.findHelper(name); |
525 world, helpers.findHelper(name), compiler.globalDependencies); | 518 impactBuilder.registerStaticUse(new StaticUse.foreignUse(element)); |
519 backend.registerBackendUse(element); | |
520 compiler.globalDependencies.registerDependency(element); | |
526 } | 521 } |
527 | 522 |
528 staticUse('defineProperty'); | 523 staticUse('defineProperty'); |
529 staticUse('toStringForNativeObject'); | 524 staticUse('toStringForNativeObject'); |
530 staticUse('hashCodeForNativeObject'); | 525 staticUse('hashCodeForNativeObject'); |
531 staticUse('convertDartClosureToJS'); | 526 staticUse('convertDartClosureToJS'); |
532 addNativeExceptions(); | 527 return _findNativeExceptions(); |
533 } | 528 } |
534 | 529 |
535 addNativeExceptions() { | 530 Iterable<ClassElement> _findNativeExceptions() { |
536 enqueueUnusedClassesMatching((classElement) { | 531 return _findUnusedClassesMatching((classElement) { |
537 // TODO(sra): Annotate exception classes in dart:html. | 532 // TODO(sra): Annotate exception classes in dart:html. |
538 String name = classElement.name; | 533 String name = classElement.name; |
539 if (name.contains('Exception')) return true; | 534 if (name.contains('Exception')) return true; |
540 if (name.contains('Error')) return true; | 535 if (name.contains('Error')) return true; |
541 return false; | 536 return false; |
542 }, 'native exception'); | 537 }); |
543 } | 538 } |
544 } | 539 } |
545 | 540 |
546 class NativeResolutionEnqueuer extends NativeEnqueuerBase { | 541 class NativeResolutionEnqueuer extends NativeEnqueuerBase { |
547 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); | 542 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); |
548 | 543 |
549 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) | 544 NativeResolutionEnqueuer(Compiler compiler) |
550 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); | 545 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
551 | 546 |
552 void processNativeClass(ClassElement classElement) { | 547 void processNativeClass(ClassElement classElement) { |
553 super.processNativeClass(classElement); | 548 super.processNativeClass(classElement); |
554 | 549 |
555 // Js Interop interfaces do not have tags. | 550 // Js Interop interfaces do not have tags. |
556 if (backend.isJsInterop(classElement)) return; | 551 if (backend.isJsInterop(classElement)) return; |
557 // Since we map from dispatch tags to classes, a dispatch tag must be used | 552 // Since we map from dispatch tags to classes, a dispatch tag must be used |
558 // on only one native class. | 553 // on only one native class. |
559 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { | 554 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { |
560 ClassElement owner = tagOwner[tag]; | 555 ClassElement owner = tagOwner[tag]; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 return NativeBehavior.ofJsBuiltinCallSend( | 611 return NativeBehavior.ofJsBuiltinCallSend( |
617 node, reporter, compiler.coreTypes, resolver); | 612 node, reporter, compiler.coreTypes, resolver); |
618 } | 613 } |
619 } | 614 } |
620 | 615 |
621 class NativeCodegenEnqueuer extends NativeEnqueuerBase { | 616 class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
622 final CodeEmitterTask emitter; | 617 final CodeEmitterTask emitter; |
623 | 618 |
624 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); | 619 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); |
625 | 620 |
626 NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter) | 621 NativeCodegenEnqueuer(Compiler compiler, this.emitter) |
627 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); | 622 : super(compiler, compiler.options.enableNativeLiveTypeAnalysis); |
628 | 623 |
629 void processNativeClasses(Iterable<LibraryElement> libraries) { | 624 void processNativeClasses( |
630 super.processNativeClasses(libraries); | 625 WorldImpactBuilder impactBuilder, Iterable<LibraryElement> libraries) { |
626 super.processNativeClasses(impactBuilder, libraries); | |
631 | 627 |
632 // HACK HACK - add all the resolved classes. | 628 // HACK HACK - add all the resolved classes. |
633 NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; | 629 NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; |
630 Set<ClassElement> matchingClasses = new Set<ClassElement>(); | |
634 for (final classElement in enqueuer.registeredClasses) { | 631 for (final classElement in enqueuer.registeredClasses) { |
635 if (unusedClasses.contains(classElement)) { | 632 if (unusedClasses.contains(classElement)) { |
636 enqueueClass(classElement, 'was resolved'); | 633 matchingClasses.add(classElement); |
637 } | 634 } |
638 } | 635 } |
639 flushQueue(); | 636 if (matchingClasses.isNotEmpty && registeredClasses.isEmpty) { |
637 matchingClasses.addAll(_onFirstNativeClass(impactBuilder)); | |
638 } | |
639 _registerTypeUses(impactBuilder, matchingClasses, 'was resolved'); | |
640 } | 640 } |
641 | 641 |
642 processClass(ClassElement classElement, cause) { | 642 void _registerTypeUses( |
643 super.processClass(classElement, cause); | 643 WorldImpactBuilder impactBuilder, Set<ClassElement> classes, cause) { |
644 // Add the information that this class is a subtype of its supertypes. The | 644 super._registerTypeUses(impactBuilder, classes, cause); |
645 // code emitter and the ssa builder use that information. | 645 |
646 addSubtypes(classElement, emitter.nativeEmitter); | 646 for (ClassElement classElement in classes) { |
647 // Add the information that this class is a subtype of its supertypes. Th e | |
Harry Terkelsen
2016/11/11 21:24:27
long line
Johnni Winther
2016/11/14 09:08:36
Done.
| |
648 // code emitter and the ssa builder use that information. | |
649 _addSubtypes(classElement, emitter.nativeEmitter); | |
650 } | |
647 } | 651 } |
648 | 652 |
649 void addSubtypes(ClassElement cls, NativeEmitter emitter) { | 653 void _addSubtypes(ClassElement cls, NativeEmitter emitter) { |
650 if (!backend.isNative(cls)) return; | 654 if (!backend.isNative(cls)) return; |
651 if (doneAddSubtypes.contains(cls)) return; | 655 if (doneAddSubtypes.contains(cls)) return; |
652 doneAddSubtypes.add(cls); | 656 doneAddSubtypes.add(cls); |
653 | 657 |
654 // Walk the superclass chain since classes on the superclass chain might not | 658 // Walk the superclass chain since classes on the superclass chain might not |
655 // be instantiated (abstract or simply unused). | 659 // be instantiated (abstract or simply unused). |
656 addSubtypes(cls.superclass, emitter); | 660 _addSubtypes(cls.superclass, emitter); |
657 | 661 |
658 for (DartType type in cls.allSupertypes) { | 662 for (DartType type in cls.allSupertypes) { |
659 List<Element> subtypes = | 663 List<Element> subtypes = |
660 emitter.subtypes.putIfAbsent(type.element, () => <ClassElement>[]); | 664 emitter.subtypes.putIfAbsent(type.element, () => <ClassElement>[]); |
661 subtypes.add(cls); | 665 subtypes.add(cls); |
662 } | 666 } |
663 | 667 |
664 // Skip through all the mixin applications in the super class | 668 // Skip through all the mixin applications in the super class |
665 // chain. That way, the direct subtypes set only contain the | 669 // chain. That way, the direct subtypes set only contain the |
666 // natives classes. | 670 // natives classes. |
667 ClassElement superclass = cls.superclass; | 671 ClassElement superclass = cls.superclass; |
668 while (superclass != null && superclass.isMixinApplication) { | 672 while (superclass != null && superclass.isMixinApplication) { |
669 assert(!backend.isNative(superclass)); | 673 assert(!backend.isNative(superclass)); |
670 superclass = superclass.superclass; | 674 superclass = superclass.superclass; |
671 } | 675 } |
672 | 676 |
673 List<Element> directSubtypes = | 677 List<Element> directSubtypes = |
674 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassElement>[]); | 678 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassElement>[]); |
675 directSubtypes.add(cls); | 679 directSubtypes.add(cls); |
676 } | 680 } |
677 | 681 |
678 void logSummary(log(message)) { | 682 void logSummary(log(message)) { |
679 log('Compiled ${registeredClasses.length} native classes, ' | 683 log('Compiled ${registeredClasses.length} native classes, ' |
680 '${unusedClasses.length} native classes omitted.'); | 684 '${unusedClasses.length} native classes omitted.'); |
681 } | 685 } |
682 } | 686 } |
OLD | NEW |