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 | 8 import '../common/backend_api.dart' show ForeignResolver; |
9 ForeignResolver; | 9 import '../common/registry.dart' show Registry; |
10 import '../common/registry.dart' show | 10 import '../common/resolution.dart' show Parsing, Resolution; |
11 Registry; | 11 import '../compiler.dart' show Compiler; |
12 import '../common/resolution.dart' show | |
13 Parsing, | |
14 Resolution; | |
15 import '../compiler.dart' show | |
16 Compiler; | |
17 import '../constants/values.dart'; | 12 import '../constants/values.dart'; |
18 import '../core_types.dart' show | 13 import '../core_types.dart' show CoreTypes; |
19 CoreTypes; | |
20 import '../dart_types.dart'; | 14 import '../dart_types.dart'; |
21 import '../enqueue.dart' show | 15 import '../enqueue.dart' show Enqueuer, ResolutionEnqueuer; |
22 Enqueuer, | |
23 ResolutionEnqueuer; | |
24 import '../elements/elements.dart'; | 16 import '../elements/elements.dart'; |
25 import '../elements/modelx.dart' show | 17 import '../elements/modelx.dart' |
26 BaseClassElementX, | 18 show BaseClassElementX, ElementX, FunctionElementX, LibraryElementX; |
27 ElementX, | 19 import '../js_backend/backend_helpers.dart' show BackendHelpers; |
28 FunctionElementX, | |
29 LibraryElementX; | |
30 import '../js_backend/backend_helpers.dart' show | |
31 BackendHelpers; | |
32 import '../js_backend/js_backend.dart'; | 20 import '../js_backend/js_backend.dart'; |
33 import '../js_emitter/js_emitter.dart' show | 21 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter; |
34 CodeEmitterTask, | 22 import '../tokens/token.dart' show BeginGroupToken, Token; |
35 NativeEmitter; | 23 import '../tokens/token_constants.dart' as Tokens show EOF_TOKEN, STRING_TOKEN; |
36 import '../tokens/token.dart' show | |
37 BeginGroupToken, | |
38 Token; | |
39 import '../tokens/token_constants.dart' as Tokens show | |
40 EOF_TOKEN, | |
41 STRING_TOKEN; | |
42 import '../tree/tree.dart'; | 24 import '../tree/tree.dart'; |
43 | 25 |
44 import 'behavior.dart'; | 26 import 'behavior.dart'; |
45 | 27 |
46 /** | 28 /** |
47 * 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. |
48 */ | 30 */ |
49 class NativeEnqueuer { | 31 class NativeEnqueuer { |
50 /// Initial entry point to native enqueuer. | 32 /// Initial entry point to native enqueuer. |
51 void processNativeClasses(Iterable<LibraryElement> libraries) {} | 33 void processNativeClasses(Iterable<LibraryElement> libraries) {} |
(...skipping 23 matching lines...) Expand all Loading... |
75 | 57 |
76 /// Emits a summary information using the [log] function. | 58 /// Emits a summary information using the [log] function. |
77 void logSummary(log(message)) {} | 59 void logSummary(log(message)) {} |
78 | 60 |
79 // Do not use annotations in dart2dart. | 61 // Do not use annotations in dart2dart. |
80 ClassElement get annotationCreatesClass => null; | 62 ClassElement get annotationCreatesClass => null; |
81 ClassElement get annotationReturnsClass => null; | 63 ClassElement get annotationReturnsClass => null; |
82 ClassElement get annotationJsNameClass => null; | 64 ClassElement get annotationJsNameClass => null; |
83 } | 65 } |
84 | 66 |
85 | |
86 abstract class NativeEnqueuerBase implements NativeEnqueuer { | 67 abstract class NativeEnqueuerBase implements NativeEnqueuer { |
87 static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$'); | 68 static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$'); |
88 | 69 |
89 /** | 70 /** |
90 * The set of all native classes. Each native class is in [nativeClasses] and | 71 * The set of all native classes. Each native class is in [nativeClasses] and |
91 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. | 72 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. |
92 */ | 73 */ |
93 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); | 74 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); |
94 | 75 |
95 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); | 76 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 // | 162 // |
182 // String "A" has a potential subclass B. | 163 // String "A" has a potential subclass B. |
183 | 164 |
184 var potentialExtends = new Map<String, Set<ClassElement>>(); | 165 var potentialExtends = new Map<String, Set<ClassElement>>(); |
185 | 166 |
186 libraries.forEach((library) { | 167 libraries.forEach((library) { |
187 library.implementation.forEachLocalMember((element) { | 168 library.implementation.forEachLocalMember((element) { |
188 if (element.isClass) { | 169 if (element.isClass) { |
189 String extendsName = findExtendsNameOfClass(element); | 170 String extendsName = findExtendsNameOfClass(element); |
190 if (extendsName != null) { | 171 if (extendsName != null) { |
191 Set<ClassElement> potentialSubclasses = | 172 Set<ClassElement> potentialSubclasses = potentialExtends |
192 potentialExtends.putIfAbsent( | 173 .putIfAbsent(extendsName, () => new Set<ClassElement>()); |
193 extendsName, | |
194 () => new Set<ClassElement>()); | |
195 potentialSubclasses.add(element); | 174 potentialSubclasses.add(element); |
196 } | 175 } |
197 } | 176 } |
198 }); | 177 }); |
199 }); | 178 }); |
200 | 179 |
201 // Resolve all the native classes and any classes that might extend them in | 180 // Resolve all the native classes and any classes that might extend them in |
202 // [potentialExtends], and then check that the properly resolved class is in | 181 // [potentialExtends], and then check that the properly resolved class is in |
203 // fact a subclass of a native class. | 182 // fact a subclass of a native class. |
204 | 183 |
205 ClassElement nativeSuperclassOf(ClassElement classElement) { | 184 ClassElement nativeSuperclassOf(ClassElement classElement) { |
206 if (backend.isNative(classElement)) return classElement; | 185 if (backend.isNative(classElement)) return classElement; |
207 if (classElement.superclass == null) return null; | 186 if (classElement.superclass == null) return null; |
208 return nativeSuperclassOf(classElement.superclass); | 187 return nativeSuperclassOf(classElement.superclass); |
209 } | 188 } |
210 | 189 |
211 void walkPotentialSubclasses(ClassElement element) { | 190 void walkPotentialSubclasses(ClassElement element) { |
212 if (nativeClassesAndSubclasses.contains(element)) return; | 191 if (nativeClassesAndSubclasses.contains(element)) return; |
213 element.ensureResolved(resolution); | 192 element.ensureResolved(resolution); |
214 ClassElement nativeSuperclass = nativeSuperclassOf(element); | 193 ClassElement nativeSuperclass = nativeSuperclassOf(element); |
215 if (nativeSuperclass != null) { | 194 if (nativeSuperclass != null) { |
216 nativeClassesAndSubclasses.add(element); | 195 nativeClassesAndSubclasses.add(element); |
217 if (!backend.isNative(element)) { | 196 if (!backend.isNative(element)) { |
218 nonNativeSubclasses.putIfAbsent(nativeSuperclass, | 197 nonNativeSubclasses |
219 () => new Set<ClassElement>()) | 198 .putIfAbsent(nativeSuperclass, () => new Set<ClassElement>()) |
220 .add(element); | 199 .add(element); |
221 } | 200 } |
222 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; | 201 Set<ClassElement> potentialSubclasses = potentialExtends[element.name]; |
223 if (potentialSubclasses != null) { | 202 if (potentialSubclasses != null) { |
224 potentialSubclasses.forEach(walkPotentialSubclasses); | 203 potentialSubclasses.forEach(walkPotentialSubclasses); |
225 } | 204 } |
226 } | 205 } |
227 } | 206 } |
228 | 207 |
229 nativeClasses.forEach(walkPotentialSubclasses); | 208 nativeClasses.forEach(walkPotentialSubclasses); |
230 | 209 |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 annotation.ensureResolved(resolution); | 320 annotation.ensureResolved(resolution); |
342 ConstantValue value = | 321 ConstantValue value = |
343 compiler.constants.getConstantValue(annotation.constant); | 322 compiler.constants.getConstantValue(annotation.constant); |
344 if (!value.isConstructedObject) continue; | 323 if (!value.isConstructedObject) continue; |
345 ConstructedConstantValue constructedObject = value; | 324 ConstructedConstantValue constructedObject = value; |
346 if (constructedObject.type.element != annotationClass) continue; | 325 if (constructedObject.type.element != annotationClass) continue; |
347 | 326 |
348 Iterable<ConstantValue> fields = constructedObject.fields.values; | 327 Iterable<ConstantValue> fields = constructedObject.fields.values; |
349 // TODO(sra): Better validation of the constant. | 328 // TODO(sra): Better validation of the constant. |
350 if (fields.length != 1 || fields.single is! StringConstantValue) { | 329 if (fields.length != 1 || fields.single is! StringConstantValue) { |
351 reporter.internalError(annotation, | 330 reporter.internalError( |
352 'Annotations needs one string: ${annotation.node}'); | 331 annotation, 'Annotations needs one string: ${annotation.node}'); |
353 } | 332 } |
354 StringConstantValue specStringConstant = fields.single; | 333 StringConstantValue specStringConstant = fields.single; |
355 String specString = specStringConstant.toDartString().slowToString(); | 334 String specString = specStringConstant.toDartString().slowToString(); |
356 if (name == null) { | 335 if (name == null) { |
357 name = specString; | 336 name = specString; |
358 } else { | 337 } else { |
359 reporter.internalError(annotation, | 338 reporter.internalError( |
360 'Too many JSName annotations: ${annotation.node}'); | 339 annotation, 'Too many JSName annotations: ${annotation.node}'); |
361 } | 340 } |
362 } | 341 } |
363 return name; | 342 return name; |
364 } | 343 } |
365 | 344 |
366 enqueueClass(ClassElement classElement, cause) { | 345 enqueueClass(ClassElement classElement, cause) { |
367 assert(unusedClasses.contains(classElement)); | 346 assert(unusedClasses.contains(classElement)); |
368 unusedClasses.remove(classElement); | 347 unusedClasses.remove(classElement); |
369 pendingClasses.add(classElement); | 348 pendingClasses.add(classElement); |
370 queue.add(() { processClass(classElement, cause); }); | 349 queue.add(() { |
| 350 processClass(classElement, cause); |
| 351 }); |
371 } | 352 } |
372 | 353 |
373 void flushQueue() { | 354 void flushQueue() { |
374 if (flushing) return; | 355 if (flushing) return; |
375 flushing = true; | 356 flushing = true; |
376 while (!queue.isEmpty) { | 357 while (!queue.isEmpty) { |
377 (queue.removeFirst())(); | 358 (queue.removeFirst())(); |
378 } | 359 } |
379 flushing = false; | 360 flushing = false; |
380 } | 361 } |
381 | 362 |
382 processClass(ClassElement classElement, cause) { | 363 processClass(ClassElement classElement, cause) { |
383 // TODO(ahe): Fix this assertion to work in incremental compilation. | 364 // TODO(ahe): Fix this assertion to work in incremental compilation. |
384 assert(compiler.options.hasIncrementalSupport || | 365 assert(compiler.options.hasIncrementalSupport || |
385 !registeredClasses.contains(classElement)); | 366 !registeredClasses.contains(classElement)); |
386 | 367 |
387 bool firstTime = registeredClasses.isEmpty; | 368 bool firstTime = registeredClasses.isEmpty; |
388 pendingClasses.remove(classElement); | 369 pendingClasses.remove(classElement); |
389 registeredClasses.add(classElement); | 370 registeredClasses.add(classElement); |
390 | 371 |
391 // TODO(ahe): Is this really a global dependency? | 372 // TODO(ahe): Is this really a global dependency? |
392 classElement.ensureResolved(resolution); | 373 classElement.ensureResolved(resolution); |
393 compiler.backend.registerInstantiatedType( | 374 compiler.backend.registerInstantiatedType( |
394 classElement.rawType, world, compiler.globalDependencies); | 375 classElement.rawType, world, compiler.globalDependencies); |
395 | 376 |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 /// use the declared @JSName as the expression | 443 /// use the declared @JSName as the expression |
463 /// 3. If [element] does not have a @JSName annotation, qualify the name of | 444 /// 3. If [element] does not have a @JSName annotation, qualify the name of |
464 /// the method with the @Native name of the enclosing class. | 445 /// the method with the @Native name of the enclosing class. |
465 void _setNativeNameForStaticMethod(MethodElement element) { | 446 void _setNativeNameForStaticMethod(MethodElement element) { |
466 String name = findJsNameFromAnnotation(element); | 447 String name = findJsNameFromAnnotation(element); |
467 if (name == null) name = element.name; | 448 if (name == null) name = element.name; |
468 if (isIdentifier(name)) { | 449 if (isIdentifier(name)) { |
469 List<String> nativeNames = | 450 List<String> nativeNames = |
470 backend.nativeData.getNativeTagsOfClassRaw(element.enclosingClass); | 451 backend.nativeData.getNativeTagsOfClassRaw(element.enclosingClass); |
471 if (nativeNames.length != 1) { | 452 if (nativeNames.length != 1) { |
472 reporter.internalError(element, | 453 reporter.internalError( |
| 454 element, |
473 'Unable to determine a native name for the enclosing class, ' | 455 'Unable to determine a native name for the enclosing class, ' |
474 'options: $nativeNames'); | 456 'options: $nativeNames'); |
475 } | 457 } |
476 backend.nativeData.setNativeMemberName( | 458 backend.nativeData |
477 element, '${nativeNames[0]}.$name'); | 459 .setNativeMemberName(element, '${nativeNames[0]}.$name'); |
478 } else { | 460 } else { |
479 backend.nativeData.setNativeMemberName(element, name); | 461 backend.nativeData.setNativeMemberName(element, name); |
480 } | 462 } |
481 } | 463 } |
482 | 464 |
483 bool isIdentifier(String s) => _identifier.hasMatch(s); | 465 bool isIdentifier(String s) => _identifier.hasMatch(s); |
484 | 466 |
485 bool isNativeMethod(FunctionElementX element) { | 467 bool isNativeMethod(FunctionElementX element) { |
486 if (!backend.canLibraryUseNative(element.library)) return false; | 468 if (!backend.canLibraryUseNative(element.library)) return false; |
487 // Native method? | 469 // Native method? |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 continue; | 512 continue; |
531 } | 513 } |
532 if (type is InterfaceType) { | 514 if (type is InterfaceType) { |
533 if (type == coreTypes.intType) { | 515 if (type == coreTypes.intType) { |
534 backend.registerInstantiatedType(type, world, registry); | 516 backend.registerInstantiatedType(type, world, registry); |
535 } else if (type == coreTypes.doubleType) { | 517 } else if (type == coreTypes.doubleType) { |
536 backend.registerInstantiatedType(type, world, registry); | 518 backend.registerInstantiatedType(type, world, registry); |
537 } else if (type == coreTypes.numType) { | 519 } else if (type == coreTypes.numType) { |
538 backend.registerInstantiatedType( | 520 backend.registerInstantiatedType( |
539 coreTypes.doubleType, world, registry); | 521 coreTypes.doubleType, world, registry); |
540 backend.registerInstantiatedType( | 522 backend.registerInstantiatedType(coreTypes.intType, world, registry); |
541 coreTypes.intType, world, registry); | |
542 } else if (type == coreTypes.stringType) { | 523 } else if (type == coreTypes.stringType) { |
543 backend.registerInstantiatedType(type, world, registry); | 524 backend.registerInstantiatedType(type, world, registry); |
544 } else if (type == coreTypes.nullType) { | 525 } else if (type == coreTypes.nullType) { |
545 backend.registerInstantiatedType(type, world, registry); | 526 backend.registerInstantiatedType(type, world, registry); |
546 } else if (type == coreTypes.boolType) { | 527 } else if (type == coreTypes.boolType) { |
547 backend.registerInstantiatedType(type, world, registry); | 528 backend.registerInstantiatedType(type, world, registry); |
548 } else if (compiler.types.isSubtype( | 529 } else if (compiler.types |
549 type, backend.listImplementation.rawType)) { | 530 .isSubtype(type, backend.listImplementation.rawType)) { |
550 backend.registerInstantiatedType(type, world, registry); | 531 backend.registerInstantiatedType(type, world, registry); |
551 } | 532 } |
552 } | 533 } |
553 assert(type is DartType); | 534 assert(type is DartType); |
554 enqueueUnusedClassesMatching( | 535 enqueueUnusedClassesMatching( |
555 (nativeClass) => compiler.types.isSubtype(nativeClass.thisType, type), | 536 (nativeClass) => compiler.types.isSubtype(nativeClass.thisType, type), |
556 cause, | 537 cause, |
557 'subtypeof($type)'); | 538 'subtypeof($type)'); |
558 } | 539 } |
559 | 540 |
560 // Give an info so that library developers can compile with -v to find why | 541 // Give an info so that library developers can compile with -v to find why |
561 // all the native classes are included. | 542 // all the native classes are included. |
562 if (unusedClasses.isEmpty && !allUsedBefore) { | 543 if (unusedClasses.isEmpty && !allUsedBefore) { |
563 reporter.log('All native types marked as used due to $cause.'); | 544 reporter.log('All native types marked as used due to $cause.'); |
564 } | 545 } |
565 } | 546 } |
566 | 547 |
567 enqueueUnusedClassesMatching(bool predicate(classElement), | 548 enqueueUnusedClassesMatching(bool predicate(classElement), cause, |
568 cause, | 549 [String reason]) { |
569 [String reason]) { | |
570 Iterable matches = unusedClasses.where(predicate); | 550 Iterable matches = unusedClasses.where(predicate); |
571 matches.toList().forEach((c) => enqueueClass(c, cause)); | 551 matches.toList().forEach((c) => enqueueClass(c, cause)); |
572 } | 552 } |
573 | 553 |
574 onFirstNativeClass() { | 554 onFirstNativeClass() { |
575 staticUse(name) { | 555 staticUse(name) { |
576 backend.enqueue( | 556 backend.enqueue( |
577 world, helpers.findHelper(name), compiler.globalDependencies); | 557 world, helpers.findHelper(name), compiler.globalDependencies); |
578 } | 558 } |
579 | 559 |
580 staticUse('defineProperty'); | 560 staticUse('defineProperty'); |
581 staticUse('toStringForNativeObject'); | 561 staticUse('toStringForNativeObject'); |
582 staticUse('hashCodeForNativeObject'); | 562 staticUse('hashCodeForNativeObject'); |
583 staticUse('convertDartClosureToJS'); | 563 staticUse('convertDartClosureToJS'); |
584 addNativeExceptions(); | 564 addNativeExceptions(); |
585 } | 565 } |
586 | 566 |
587 addNativeExceptions() { | 567 addNativeExceptions() { |
588 enqueueUnusedClassesMatching((classElement) { | 568 enqueueUnusedClassesMatching((classElement) { |
589 // TODO(sra): Annotate exception classes in dart:html. | 569 // TODO(sra): Annotate exception classes in dart:html. |
590 String name = classElement.name; | 570 String name = classElement.name; |
591 if (name.contains('Exception')) return true; | 571 if (name.contains('Exception')) return true; |
592 if (name.contains('Error')) return true; | 572 if (name.contains('Error')) return true; |
593 return false; | 573 return false; |
594 }, | 574 }, 'native exception'); |
595 'native exception'); | |
596 } | 575 } |
597 } | 576 } |
598 | 577 |
599 | |
600 class NativeResolutionEnqueuer extends NativeEnqueuerBase { | 578 class NativeResolutionEnqueuer extends NativeEnqueuerBase { |
601 | |
602 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); | 579 Map<String, ClassElement> tagOwner = new Map<String, ClassElement>(); |
603 | 580 |
604 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) | 581 NativeResolutionEnqueuer(Enqueuer world, Compiler compiler) |
605 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); | 582 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); |
606 | 583 |
607 void processNativeClass(ClassElement classElement) { | 584 void processNativeClass(ClassElement classElement) { |
608 super.processNativeClass(classElement); | 585 super.processNativeClass(classElement); |
609 | 586 |
610 // Js Interop interfaces do not have tags. | 587 // Js Interop interfaces do not have tags. |
611 if (backend.isJsInterop(classElement)) return; | 588 if (backend.isJsInterop(classElement)) return; |
612 // Since we map from dispatch tags to classes, a dispatch tag must be used | 589 // Since we map from dispatch tags to classes, a dispatch tag must be used |
613 // on only one native class. | 590 // on only one native class. |
614 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { | 591 for (String tag in backend.nativeData.getNativeTagsOfClass(classElement)) { |
615 ClassElement owner = tagOwner[tag]; | 592 ClassElement owner = tagOwner[tag]; |
(...skipping 22 matching lines...) Expand all Loading... |
638 * JS('_DOMWindowImpl', 'window') | 615 * JS('_DOMWindowImpl', 'window') |
639 * | 616 * |
640 */ | 617 */ |
641 void registerJsCall(Send node, ForeignResolver resolver) { | 618 void registerJsCall(Send node, ForeignResolver resolver) { |
642 NativeBehavior behavior = NativeBehavior.ofJsCall( | 619 NativeBehavior behavior = NativeBehavior.ofJsCall( |
643 node, reporter, compiler.parsing, compiler.coreTypes, resolver); | 620 node, reporter, compiler.parsing, compiler.coreTypes, resolver); |
644 registerNativeBehavior(behavior, node); | 621 registerNativeBehavior(behavior, node); |
645 nativeBehaviors[node] = behavior; | 622 nativeBehaviors[node] = behavior; |
646 } | 623 } |
647 | 624 |
648 | |
649 /** | 625 /** |
650 * Handles JS-embedded global calls, which can be an instantiation point for | 626 * Handles JS-embedded global calls, which can be an instantiation point for |
651 * types. | 627 * types. |
652 * | 628 * |
653 * For example, the following code instantiates and returns a String class | 629 * For example, the following code instantiates and returns a String class |
654 * | 630 * |
655 * JS_EMBEDDED_GLOBAL('String', 'foo') | 631 * JS_EMBEDDED_GLOBAL('String', 'foo') |
656 * | 632 * |
657 */ | 633 */ |
658 void registerJsEmbeddedGlobalCall(Send node, ForeignResolver resolver) { | 634 void registerJsEmbeddedGlobalCall(Send node, ForeignResolver resolver) { |
659 NativeBehavior behavior = NativeBehavior.ofJsEmbeddedGlobalCall( | 635 NativeBehavior behavior = NativeBehavior.ofJsEmbeddedGlobalCall( |
660 node, reporter, compiler.parsing, compiler.coreTypes, resolver); | 636 node, reporter, compiler.parsing, compiler.coreTypes, resolver); |
661 registerNativeBehavior(behavior, node); | 637 registerNativeBehavior(behavior, node); |
662 nativeBehaviors[node] = behavior; | 638 nativeBehaviors[node] = behavior; |
663 } | 639 } |
664 | 640 |
665 | |
666 /** | 641 /** |
667 * Handles JS-compiler builtin calls, which can be an instantiation point for | 642 * Handles JS-compiler builtin calls, which can be an instantiation point for |
668 * types. | 643 * types. |
669 * | 644 * |
670 * For example, the following code instantiates and returns a String class | 645 * For example, the following code instantiates and returns a String class |
671 * | 646 * |
672 * JS_BUILTIN('String', 'int2string', 0) | 647 * JS_BUILTIN('String', 'int2string', 0) |
673 * | 648 * |
674 */ | 649 */ |
675 void registerJsBuiltinCall(Send node, ForeignResolver resolver) { | 650 void registerJsBuiltinCall(Send node, ForeignResolver resolver) { |
676 NativeBehavior behavior = NativeBehavior.ofJsBuiltinCall( | 651 NativeBehavior behavior = NativeBehavior.ofJsBuiltinCall( |
677 node, reporter, compiler.parsing, compiler.coreTypes, resolver); | 652 node, reporter, compiler.parsing, compiler.coreTypes, resolver); |
678 registerNativeBehavior(behavior, node); | 653 registerNativeBehavior(behavior, node); |
679 nativeBehaviors[node] = behavior; | 654 nativeBehaviors[node] = behavior; |
680 } | 655 } |
681 } | 656 } |
682 | 657 |
683 | |
684 class NativeCodegenEnqueuer extends NativeEnqueuerBase { | 658 class NativeCodegenEnqueuer extends NativeEnqueuerBase { |
685 | |
686 final CodeEmitterTask emitter; | 659 final CodeEmitterTask emitter; |
687 | 660 |
688 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); | 661 final Set<ClassElement> doneAddSubtypes = new Set<ClassElement>(); |
689 | 662 |
690 NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter) | 663 NativeCodegenEnqueuer(Enqueuer world, Compiler compiler, this.emitter) |
691 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); | 664 : super(world, compiler, compiler.options.enableNativeLiveTypeAnalysis); |
692 | 665 |
693 void processNativeClasses(Iterable<LibraryElement> libraries) { | 666 void processNativeClasses(Iterable<LibraryElement> libraries) { |
694 super.processNativeClasses(libraries); | 667 super.processNativeClasses(libraries); |
695 | 668 |
696 // HACK HACK - add all the resolved classes. | 669 // HACK HACK - add all the resolved classes. |
697 NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; | 670 NativeEnqueuerBase enqueuer = compiler.enqueuer.resolution.nativeEnqueuer; |
698 for (final classElement in enqueuer.registeredClasses) { | 671 for (final classElement in enqueuer.registeredClasses) { |
699 if (unusedClasses.contains(classElement)) { | 672 if (unusedClasses.contains(classElement)) { |
700 enqueueClass(classElement, 'was resolved'); | 673 enqueueClass(classElement, 'was resolved'); |
701 } | 674 } |
(...skipping 11 matching lines...) Expand all Loading... |
713 void addSubtypes(ClassElement cls, NativeEmitter emitter) { | 686 void addSubtypes(ClassElement cls, NativeEmitter emitter) { |
714 if (!backend.isNative(cls)) return; | 687 if (!backend.isNative(cls)) return; |
715 if (doneAddSubtypes.contains(cls)) return; | 688 if (doneAddSubtypes.contains(cls)) return; |
716 doneAddSubtypes.add(cls); | 689 doneAddSubtypes.add(cls); |
717 | 690 |
718 // Walk the superclass chain since classes on the superclass chain might not | 691 // Walk the superclass chain since classes on the superclass chain might not |
719 // be instantiated (abstract or simply unused). | 692 // be instantiated (abstract or simply unused). |
720 addSubtypes(cls.superclass, emitter); | 693 addSubtypes(cls.superclass, emitter); |
721 | 694 |
722 for (DartType type in cls.allSupertypes) { | 695 for (DartType type in cls.allSupertypes) { |
723 List<Element> subtypes = emitter.subtypes.putIfAbsent( | 696 List<Element> subtypes = |
724 type.element, | 697 emitter.subtypes.putIfAbsent(type.element, () => <ClassElement>[]); |
725 () => <ClassElement>[]); | |
726 subtypes.add(cls); | 698 subtypes.add(cls); |
727 } | 699 } |
728 | 700 |
729 // Skip through all the mixin applications in the super class | 701 // Skip through all the mixin applications in the super class |
730 // chain. That way, the direct subtypes set only contain the | 702 // chain. That way, the direct subtypes set only contain the |
731 // natives classes. | 703 // natives classes. |
732 ClassElement superclass = cls.superclass; | 704 ClassElement superclass = cls.superclass; |
733 while (superclass != null && superclass.isMixinApplication) { | 705 while (superclass != null && superclass.isMixinApplication) { |
734 assert(!backend.isNative(superclass)); | 706 assert(!backend.isNative(superclass)); |
735 superclass = superclass.superclass; | 707 superclass = superclass.superclass; |
736 } | 708 } |
737 | 709 |
738 List<Element> directSubtypes = emitter.directSubtypes.putIfAbsent( | 710 List<Element> directSubtypes = |
739 superclass, | 711 emitter.directSubtypes.putIfAbsent(superclass, () => <ClassElement>[]); |
740 () => <ClassElement>[]); | |
741 directSubtypes.add(cls); | 712 directSubtypes.add(cls); |
742 } | 713 } |
743 | 714 |
744 void logSummary(log(message)) { | 715 void logSummary(log(message)) { |
745 log('Compiled ${registeredClasses.length} native classes, ' | 716 log('Compiled ${registeredClasses.length} native classes, ' |
746 '${unusedClasses.length} native classes omitted.'); | 717 '${unusedClasses.length} native classes omitted.'); |
747 } | 718 } |
748 } | 719 } |
OLD | NEW |