OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library js_backend.namer; | 5 library js_backend.namer; |
6 | 6 |
7 import 'dart:collection' show HashMap; | 7 import 'dart:collection' show HashMap; |
8 | 8 |
9 import 'package:js_runtime/shared/embedded_names.dart' show JsGetName; | 9 import 'package:js_runtime/shared/embedded_names.dart' show JsGetName; |
10 | 10 |
11 import '../closure.dart'; | 11 import '../closure.dart'; |
12 import '../common.dart'; | 12 import '../common.dart'; |
13 import '../common/names.dart' show Identifiers, Selectors; | 13 import '../common/names.dart' show Identifiers, Selectors; |
14 import '../constants/values.dart'; | 14 import '../constants/values.dart'; |
15 import '../common_elements.dart' show CommonElements; | 15 import '../common_elements.dart' show CommonElements; |
16 import '../diagnostics/invariant.dart' show DEBUG_MODE; | 16 import '../diagnostics/invariant.dart' show DEBUG_MODE; |
17 import '../elements/elements.dart'; | 17 import '../elements/elements.dart'; |
18 import '../elements/entities.dart'; | 18 import '../elements/entities.dart'; |
19 import '../elements/resolution_types.dart'; | 19 import '../elements/resolution_types.dart'; |
20 import '../elements/types.dart'; | 20 import '../elements/types.dart'; |
21 import '../js/js.dart' as jsAst; | 21 import '../js/js.dart' as jsAst; |
22 import '../js/js.dart' show js; | |
23 import '../tree/tree.dart'; | 22 import '../tree/tree.dart'; |
24 import '../universe/call_structure.dart' show CallStructure; | 23 import '../universe/call_structure.dart' show CallStructure; |
25 import '../universe/selector.dart' show Selector, SelectorKind; | 24 import '../universe/selector.dart' show Selector, SelectorKind; |
26 import '../universe/world_builder.dart' show CodegenWorldBuilder; | 25 import '../universe/world_builder.dart' show CodegenWorldBuilder; |
27 import 'package:front_end/src/fasta/scanner/characters.dart'; | 26 import 'package:front_end/src/fasta/scanner/characters.dart'; |
28 import '../util/util.dart'; | 27 import '../util/util.dart'; |
29 import '../world.dart' show ClosedWorld; | 28 import '../world.dart' show ClosedWorld; |
30 import 'backend.dart'; | 29 import 'backend.dart'; |
31 import 'backend_helpers.dart'; | 30 import 'backend_helpers.dart'; |
32 import 'constant_system_javascript.dart'; | 31 import 'constant_system_javascript.dart'; |
| 32 import 'native_data.dart'; |
33 | 33 |
34 part 'field_naming_mixin.dart'; | 34 part 'field_naming_mixin.dart'; |
35 part 'frequency_namer.dart'; | 35 part 'frequency_namer.dart'; |
36 part 'minify_namer.dart'; | 36 part 'minify_namer.dart'; |
37 part 'namer_names.dart'; | 37 part 'namer_names.dart'; |
38 | 38 |
39 /** | 39 /** |
40 * Assigns JavaScript identifiers to Dart variables, class-names and members. | 40 * Assigns JavaScript identifiers to Dart variables, class-names and members. |
41 * | 41 * |
42 * Names are generated through three stages: | 42 * Names are generated through three stages: |
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 | 478 |
479 jsAst.Name _rtiFieldName; | 479 jsAst.Name _rtiFieldName; |
480 jsAst.Name get rtiFieldName => _rtiFieldName ??= new StringBackedName(r'$ti'); | 480 jsAst.Name get rtiFieldName => _rtiFieldName ??= new StringBackedName(r'$ti'); |
481 | 481 |
482 // Name of property in a class description for the native dispatch metadata. | 482 // Name of property in a class description for the native dispatch metadata. |
483 final String nativeSpecProperty = '%'; | 483 final String nativeSpecProperty = '%'; |
484 | 484 |
485 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); | 485 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); |
486 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); | 486 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); |
487 | 487 |
488 final JavaScriptBackend backend; | 488 final BackendHelpers _helpers; |
489 final ClosedWorld closedWorld; | 489 final NativeData _nativeData; |
490 final CodegenWorldBuilder codegenWorldBuilder; | 490 final ClosedWorld _closedWorld; |
| 491 final CodegenWorldBuilder _codegenWorldBuilder; |
491 | 492 |
492 RuntimeTypesEncoder _rtiEncoder; | 493 RuntimeTypesEncoder _rtiEncoder; |
493 RuntimeTypesEncoder get rtiEncoder { | 494 RuntimeTypesEncoder get rtiEncoder { |
494 assert(invariant(NO_LOCATION_SPANNABLE, _rtiEncoder != null, | 495 assert(invariant(NO_LOCATION_SPANNABLE, _rtiEncoder != null, |
495 message: "Namer.rtiEncoder has not been set.")); | 496 message: "Namer.rtiEncoder has not been set.")); |
496 return _rtiEncoder; | 497 return _rtiEncoder; |
497 } | 498 } |
498 | 499 |
499 void set rtiEncoder(RuntimeTypesEncoder value) { | 500 void set rtiEncoder(RuntimeTypesEncoder value) { |
500 assert(invariant(NO_LOCATION_SPANNABLE, _rtiEncoder == null, | 501 assert(invariant(NO_LOCATION_SPANNABLE, _rtiEncoder == null, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
550 | 551 |
551 final Map<String, String> suggestedGlobalNames = <String, String>{}; | 552 final Map<String, String> suggestedGlobalNames = <String, String>{}; |
552 final Map<String, String> suggestedInstanceNames = <String, String>{}; | 553 final Map<String, String> suggestedInstanceNames = <String, String>{}; |
553 | 554 |
554 /// Used to store unique keys for library names. Keys are not used as names, | 555 /// Used to store unique keys for library names. Keys are not used as names, |
555 /// nor are they visible in the output. The only serve as an internal | 556 /// nor are they visible in the output. The only serve as an internal |
556 /// key into maps. | 557 /// key into maps. |
557 final Map<LibraryElement, String> _libraryKeys = | 558 final Map<LibraryElement, String> _libraryKeys = |
558 new HashMap<LibraryElement, String>(); | 559 new HashMap<LibraryElement, String>(); |
559 | 560 |
560 Namer(JavaScriptBackend backend, this.closedWorld, | 561 Namer(this._helpers, this._nativeData, this._closedWorld, |
561 CodegenWorldBuilder codegenWorldBuilder) | 562 this._codegenWorldBuilder) { |
562 : this.backend = backend, | |
563 this.codegenWorldBuilder = codegenWorldBuilder { | |
564 _literalAsyncPrefix = new StringBackedName(asyncPrefix); | 563 _literalAsyncPrefix = new StringBackedName(asyncPrefix); |
565 _literalGetterPrefix = new StringBackedName(getterPrefix); | 564 _literalGetterPrefix = new StringBackedName(getterPrefix); |
566 _literalSetterPrefix = new StringBackedName(setterPrefix); | 565 _literalSetterPrefix = new StringBackedName(setterPrefix); |
567 _literalLazyGetterPrefix = new StringBackedName(lazyGetterPrefix); | 566 _literalLazyGetterPrefix = new StringBackedName(lazyGetterPrefix); |
568 } | 567 } |
569 | 568 |
570 BackendHelpers get helpers => backend.helpers; | 569 CommonElements get _commonElements => _closedWorld.commonElements; |
571 | |
572 DiagnosticReporter get reporter => backend.reporter; | |
573 | |
574 CommonElements get commonElements => closedWorld.commonElements; | |
575 | 570 |
576 String get deferredTypesName => 'deferredTypes'; | 571 String get deferredTypesName => 'deferredTypes'; |
577 String get isolateName => 'Isolate'; | 572 String get isolateName => 'Isolate'; |
578 String get isolatePropertiesName => r'$isolateProperties'; | 573 String get isolatePropertiesName => r'$isolateProperties'; |
579 jsAst.Name get noSuchMethodName => invocationName(Selectors.noSuchMethod_); | 574 jsAst.Name get noSuchMethodName => invocationName(Selectors.noSuchMethod_); |
580 | 575 |
581 /** | 576 /** |
582 * Some closures must contain their name. The name is stored in | 577 * Some closures must contain their name. The name is stored in |
583 * [STATIC_CLOSURE_NAME_NAME]. | 578 * [STATIC_CLOSURE_NAME_NAME]. |
584 */ | 579 */ |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
637 return asName(functionTypeVoidReturnTag); | 632 return asName(functionTypeVoidReturnTag); |
638 case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG: | 633 case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG: |
639 return asName(functionTypeReturnTypeTag); | 634 return asName(functionTypeReturnTypeTag); |
640 case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG: | 635 case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG: |
641 return asName(functionTypeRequiredParametersTag); | 636 return asName(functionTypeRequiredParametersTag); |
642 case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG: | 637 case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG: |
643 return asName(functionTypeOptionalParametersTag); | 638 return asName(functionTypeOptionalParametersTag); |
644 case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG: | 639 case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG: |
645 return asName(functionTypeNamedParametersTag); | 640 return asName(functionTypeNamedParametersTag); |
646 case JsGetName.IS_INDEXABLE_FIELD_NAME: | 641 case JsGetName.IS_INDEXABLE_FIELD_NAME: |
647 return operatorIs(helpers.jsIndexingBehaviorInterface); | 642 return operatorIs(_helpers.jsIndexingBehaviorInterface); |
648 case JsGetName.NULL_CLASS_TYPE_NAME: | 643 case JsGetName.NULL_CLASS_TYPE_NAME: |
649 ClassElement nullClass = commonElements.nullClass; | 644 ClassElement nullClass = _commonElements.nullClass; |
650 return runtimeTypeName(nullClass); | 645 return runtimeTypeName(nullClass); |
651 case JsGetName.OBJECT_CLASS_TYPE_NAME: | 646 case JsGetName.OBJECT_CLASS_TYPE_NAME: |
652 ClassElement objectClass = commonElements.objectClass; | 647 ClassElement objectClass = _commonElements.objectClass; |
653 return runtimeTypeName(objectClass); | 648 return runtimeTypeName(objectClass); |
654 case JsGetName.FUNCTION_CLASS_TYPE_NAME: | 649 case JsGetName.FUNCTION_CLASS_TYPE_NAME: |
655 ClassElement functionClass = commonElements.functionClass; | 650 ClassElement functionClass = _commonElements.functionClass; |
656 return runtimeTypeName(functionClass); | 651 return runtimeTypeName(functionClass); |
657 default: | 652 default: |
658 reporter.reportErrorMessage(node, MessageKind.GENERIC, | 653 throw new SpannableAssertionFailure( |
659 {'text': 'Error: Namer has no name for "$name".'}); | 654 node, 'Error: Namer has no name for "$name".'); |
660 return asName('BROKEN'); | |
661 } | 655 } |
662 } | 656 } |
663 | 657 |
664 /// Return a reference to the given [name]. | 658 /// Return a reference to the given [name]. |
665 /// | 659 /// |
666 /// This is used to ensure that every use site of a name has a unique node so | 660 /// This is used to ensure that every use site of a name has a unique node so |
667 /// that we can properly attribute source information. | 661 /// that we can properly attribute source information. |
668 jsAst.Name _newReference(jsAst.Name name) { | 662 jsAst.Name _newReference(jsAst.Name name) { |
669 return new _NameReference(name); | 663 return new _NameReference(name); |
670 } | 664 } |
(...skipping 12 matching lines...) Expand all Loading... |
683 result = getFreshName(constantScope, longName); | 677 result = getFreshName(constantScope, longName); |
684 constantNames[constant] = result; | 678 constantNames[constant] = result; |
685 } | 679 } |
686 return _newReference(result); | 680 return _newReference(result); |
687 } | 681 } |
688 | 682 |
689 /// Proposed name for [constant]. | 683 /// Proposed name for [constant]. |
690 String constantLongName(ConstantValue constant) { | 684 String constantLongName(ConstantValue constant) { |
691 String longName = constantLongNames[constant]; | 685 String longName = constantLongNames[constant]; |
692 if (longName == null) { | 686 if (longName == null) { |
693 _constantHasher ??= new ConstantCanonicalHasher( | 687 _constantHasher ??= |
694 rtiEncoder, reporter, codegenWorldBuilder); | 688 new ConstantCanonicalHasher(rtiEncoder, _codegenWorldBuilder); |
695 longName = new ConstantNamingVisitor( | 689 longName = new ConstantNamingVisitor( |
696 rtiEncoder, reporter, codegenWorldBuilder, _constantHasher) | 690 rtiEncoder, _codegenWorldBuilder, _constantHasher) |
697 .getName(constant); | 691 .getName(constant); |
698 constantLongNames[constant] = longName; | 692 constantLongNames[constant] = longName; |
699 } | 693 } |
700 return longName; | 694 return longName; |
701 } | 695 } |
702 | 696 |
703 String breakLabelName(LabelDefinition label) { | 697 String breakLabelName(LabelDefinition label) { |
704 return '\$${label.labelName}\$${label.target.nestingLevel}'; | 698 return '\$${label.labelName}\$${label.target.nestingLevel}'; |
705 } | 699 } |
706 | 700 |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
771 | 765 |
772 /// Annotated name for [method] encoding arity and named parameters. | 766 /// Annotated name for [method] encoding arity and named parameters. |
773 jsAst.Name instanceMethodName(MethodElement method) { | 767 jsAst.Name instanceMethodName(MethodElement method) { |
774 if (method.isGenerativeConstructorBody) { | 768 if (method.isGenerativeConstructorBody) { |
775 return constructorBodyName(method); | 769 return constructorBodyName(method); |
776 } | 770 } |
777 return invocationName(new Selector.fromElement(method)); | 771 return invocationName(new Selector.fromElement(method)); |
778 } | 772 } |
779 | 773 |
780 String _jsNameHelper(Element e) { | 774 String _jsNameHelper(Element e) { |
781 String jsInteropName = backend.nativeData.getJsInteropName(e); | 775 String jsInteropName = _nativeData.getJsInteropName(e); |
782 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName; | 776 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName; |
783 return e.isLibrary | 777 return e.isLibrary ? 'self' : _nativeData.getUnescapedJSInteropName(e.name); |
784 ? 'self' | |
785 : backend.nativeData.getUnescapedJSInteropName(e.name); | |
786 } | 778 } |
787 | 779 |
788 /// Returns a JavaScript path specifying the context in which | 780 /// Returns a JavaScript path specifying the context in which |
789 /// [element.fixedBackendName] should be evaluated. Only applicable for | 781 /// [element.fixedBackendName] should be evaluated. Only applicable for |
790 /// elements using typed JavaScript interop. | 782 /// elements using typed JavaScript interop. |
791 /// For example: fixedBackendPath for the static method createMap in the | 783 /// For example: fixedBackendPath for the static method createMap in the |
792 /// Map class of the goog.map JavaScript library would have path | 784 /// Map class of the goog.map JavaScript library would have path |
793 /// "goog.maps.Map". | 785 /// "goog.maps.Map". |
794 String fixedBackendMethodPath(MethodElement element) { | 786 String fixedBackendMethodPath(MethodElement element) { |
795 return _fixedBackendPath(element); | 787 return _fixedBackendPath(element); |
796 } | 788 } |
797 | 789 |
798 String _fixedBackendPath(Element element) { | 790 String _fixedBackendPath(Element element) { |
799 if (!backend.nativeData.isJsInterop(element)) return null; | 791 if (!_nativeData.isJsInterop(element)) return null; |
800 if (element.isInstanceMember) return 'this'; | 792 if (element.isInstanceMember) return 'this'; |
801 if (element.isConstructor) return _fixedBackendPath(element.enclosingClass); | 793 if (element.isConstructor) return _fixedBackendPath(element.enclosingClass); |
802 if (element.isLibrary) return 'self'; | 794 if (element.isLibrary) return 'self'; |
803 var sb = new StringBuffer(); | 795 var sb = new StringBuffer(); |
804 sb..write(_jsNameHelper(element.library)); | 796 sb..write(_jsNameHelper(element.library)); |
805 | 797 |
806 if (element.enclosingClass != null && element.enclosingClass != element) { | 798 if (element.enclosingClass != null && element.enclosingClass != element) { |
807 sb..write('.')..write(_jsNameHelper(element.enclosingClass)); | 799 sb..write('.')..write(_jsNameHelper(element.enclosingClass)); |
808 } | 800 } |
809 return sb.toString(); | 801 return sb.toString(); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
871 List<String> suffix = callSuffixForStructure(selector.callStructure); | 863 List<String> suffix = callSuffixForStructure(selector.callStructure); |
872 if (selector.name == Identifiers.call) { | 864 if (selector.name == Identifiers.call) { |
873 // Derive the annotated name for this variant of 'call'. | 865 // Derive the annotated name for this variant of 'call'. |
874 return deriveCallMethodName(suffix); | 866 return deriveCallMethodName(suffix); |
875 } | 867 } |
876 jsAst.Name disambiguatedName = | 868 jsAst.Name disambiguatedName = |
877 _disambiguateMember(selector.memberName, suffix); | 869 _disambiguateMember(selector.memberName, suffix); |
878 return disambiguatedName; // Methods other than call are not annotated. | 870 return disambiguatedName; // Methods other than call are not annotated. |
879 | 871 |
880 default: | 872 default: |
881 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | 873 throw new SpannableAssertionFailure(CURRENT_ELEMENT_SPANNABLE, |
882 'Unexpected selector kind: ${selector.kind}'); | 874 'Unexpected selector kind: ${selector.kind}'); |
883 return null; | |
884 } | 875 } |
885 } | 876 } |
886 | 877 |
887 /** | 878 /** |
888 * Returns the internal name used for an invocation mirror of this selector. | 879 * Returns the internal name used for an invocation mirror of this selector. |
889 */ | 880 */ |
890 jsAst.Name invocationMirrorInternalName(Selector selector) => | 881 jsAst.Name invocationMirrorInternalName(Selector selector) => |
891 invocationName(selector); | 882 invocationName(selector); |
892 | 883 |
893 /** | 884 /** |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
928 jsAst.Name globalPropertyName(Element element) { | 919 jsAst.Name globalPropertyName(Element element) { |
929 return _disambiguateGlobal(element); | 920 return _disambiguateGlobal(element); |
930 } | 921 } |
931 | 922 |
932 /** | 923 /** |
933 * Returns the JavaScript property name used to store an instance field. | 924 * Returns the JavaScript property name used to store an instance field. |
934 */ | 925 */ |
935 jsAst.Name instanceFieldPropertyName(FieldElement element) { | 926 jsAst.Name instanceFieldPropertyName(FieldElement element) { |
936 ClassElement enclosingClass = element.enclosingClass; | 927 ClassElement enclosingClass = element.enclosingClass; |
937 | 928 |
938 if (backend.nativeData.hasFixedBackendName(element)) { | 929 if (_nativeData.hasFixedBackendName(element)) { |
939 return new StringBackedName( | 930 return new StringBackedName(_nativeData.getFixedBackendName(element)); |
940 backend.nativeData.getFixedBackendName(element)); | |
941 } | 931 } |
942 | 932 |
943 // Some elements, like e.g. instances of BoxFieldElement are special. | 933 // Some elements, like e.g. instances of BoxFieldElement are special. |
944 // They are created with a unique and safe name for the element model. | 934 // They are created with a unique and safe name for the element model. |
945 // While their name is unique, it is not very readable. So we try to | 935 // While their name is unique, it is not very readable. So we try to |
946 // preserve the original, proposed name. | 936 // preserve the original, proposed name. |
947 // However, as boxes are not really instances of classes, the usual naming | 937 // However, as boxes are not really instances of classes, the usual naming |
948 // scheme that tries to avoid name clashes with super classes does not | 938 // scheme that tries to avoid name clashes with super classes does not |
949 // apply. So we can directly grab a name. | 939 // apply. So we can directly grab a name. |
950 Entity asEntity = element; | 940 Entity asEntity = element; |
951 if (asEntity is JSEntity) { | 941 if (asEntity is JSEntity) { |
952 return _disambiguateInternalMember( | 942 return _disambiguateInternalMember( |
953 element, () => asEntity.declaredEntity.name); | 943 element, () => asEntity.declaredEntity.name); |
954 } | 944 } |
955 | 945 |
956 // If the name of the field might clash with another field, | 946 // If the name of the field might clash with another field, |
957 // use a mangled field name to avoid potential clashes. | 947 // use a mangled field name to avoid potential clashes. |
958 // Note that if the class extends a native class, that native class might | 948 // Note that if the class extends a native class, that native class might |
959 // have fields with fixed backend names, so we assume the worst and always | 949 // have fields with fixed backend names, so we assume the worst and always |
960 // mangle the field names of classes extending native classes. | 950 // mangle the field names of classes extending native classes. |
961 // Methods on such classes are stored on the interceptor, not the instance, | 951 // Methods on such classes are stored on the interceptor, not the instance, |
962 // so only fields have the potential to clash with a native property name. | 952 // so only fields have the potential to clash with a native property name. |
963 if (closedWorld.isUsedAsMixin(enclosingClass) || | 953 if (_closedWorld.isUsedAsMixin(enclosingClass) || |
964 _isShadowingSuperField(element) || | 954 _isShadowingSuperField(element) || |
965 _isUserClassExtendingNative(enclosingClass)) { | 955 _isUserClassExtendingNative(enclosingClass)) { |
966 String proposeName() => '${enclosingClass.name}_${element.name}'; | 956 String proposeName() => '${enclosingClass.name}_${element.name}'; |
967 return _disambiguateInternalMember(element, proposeName); | 957 return _disambiguateInternalMember(element, proposeName); |
968 } | 958 } |
969 | 959 |
970 // No superclass uses the disambiguated name as a property name, so we can | 960 // No superclass uses the disambiguated name as a property name, so we can |
971 // use it for this field. This generates nicer field names since otherwise | 961 // use it for this field. This generates nicer field names since otherwise |
972 // the field name would have to be mangled. | 962 // the field name would have to be mangled. |
973 return _disambiguateMember(element.memberName); | 963 return _disambiguateMember(element.memberName); |
974 } | 964 } |
975 | 965 |
976 bool _isShadowingSuperField(Element element) { | 966 bool _isShadowingSuperField(Element element) { |
977 return element.enclosingClass.hasFieldShadowedBy(element); | 967 return element.enclosingClass.hasFieldShadowedBy(element); |
978 } | 968 } |
979 | 969 |
980 /// True if [class_] is a non-native class that inherits from a native class. | 970 /// True if [class_] is a non-native class that inherits from a native class. |
981 bool _isUserClassExtendingNative(ClassElement class_) { | 971 bool _isUserClassExtendingNative(ClassElement class_) { |
982 return !backend.nativeData.isNativeClass(class_) && | 972 return !_nativeData.isNativeClass(class_) && |
983 backend.nativeData.isNativeOrExtendsNative(class_.superclass); | 973 _nativeData.isNativeOrExtendsNative(class_.superclass); |
984 } | 974 } |
985 | 975 |
986 /// Annotated name for the setter of [element]. | 976 /// Annotated name for the setter of [element]. |
987 jsAst.Name setterForElement(MemberElement element) { | 977 jsAst.Name setterForElement(MemberElement element) { |
988 // We dynamically create setters from the field-name. The setter name must | 978 // We dynamically create setters from the field-name. The setter name must |
989 // therefore be derived from the instance field-name. | 979 // therefore be derived from the instance field-name. |
990 jsAst.Name name = _disambiguateMember(element.memberName); | 980 jsAst.Name name = _disambiguateMember(element.memberName); |
991 return deriveSetterName(name); | 981 return deriveSetterName(name); |
992 } | 982 } |
993 | 983 |
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1351 String disambiguated = name; | 1341 String disambiguated = name; |
1352 for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) { | 1342 for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) { |
1353 disambiguated = "$name$c"; | 1343 disambiguated = "$name$c"; |
1354 } | 1344 } |
1355 libraryLongNames[library] = disambiguated; | 1345 libraryLongNames[library] = disambiguated; |
1356 return disambiguated; | 1346 return disambiguated; |
1357 } | 1347 } |
1358 | 1348 |
1359 String suffixForGetInterceptor(Iterable<ClassEntity> classes) { | 1349 String suffixForGetInterceptor(Iterable<ClassEntity> classes) { |
1360 String abbreviate(ClassElement cls) { | 1350 String abbreviate(ClassElement cls) { |
1361 if (cls == commonElements.objectClass) return "o"; | 1351 if (cls == _commonElements.objectClass) return "o"; |
1362 if (cls == helpers.jsStringClass) return "s"; | 1352 if (cls == _helpers.jsStringClass) return "s"; |
1363 if (cls == helpers.jsArrayClass) return "a"; | 1353 if (cls == _helpers.jsArrayClass) return "a"; |
1364 if (cls == helpers.jsDoubleClass) return "d"; | 1354 if (cls == _helpers.jsDoubleClass) return "d"; |
1365 if (cls == helpers.jsIntClass) return "i"; | 1355 if (cls == _helpers.jsIntClass) return "i"; |
1366 if (cls == helpers.jsNumberClass) return "n"; | 1356 if (cls == _helpers.jsNumberClass) return "n"; |
1367 if (cls == helpers.jsNullClass) return "u"; | 1357 if (cls == _helpers.jsNullClass) return "u"; |
1368 if (cls == helpers.jsBoolClass) return "b"; | 1358 if (cls == _helpers.jsBoolClass) return "b"; |
1369 if (cls == helpers.jsInterceptorClass) return "I"; | 1359 if (cls == _helpers.jsInterceptorClass) return "I"; |
1370 return cls.name; | 1360 return cls.name; |
1371 } | 1361 } |
1372 | 1362 |
1373 List<String> names = classes | 1363 List<String> names = classes |
1374 .where((cls) => !backend.nativeData.isNativeOrExtendsNative(cls)) | 1364 .where((cls) => !_nativeData.isNativeOrExtendsNative(cls)) |
1375 .map(abbreviate) | 1365 .map(abbreviate) |
1376 .toList(); | 1366 .toList(); |
1377 // There is one dispatch mechanism for all native classes. | 1367 // There is one dispatch mechanism for all native classes. |
1378 if (classes.any((cls) => backend.nativeData.isNativeOrExtendsNative(cls))) { | 1368 if (classes.any((cls) => _nativeData.isNativeOrExtendsNative(cls))) { |
1379 names.add("x"); | 1369 names.add("x"); |
1380 } | 1370 } |
1381 // Sort the names of the classes after abbreviating them to ensure | 1371 // Sort the names of the classes after abbreviating them to ensure |
1382 // the suffix is stable and predictable for the suggested names. | 1372 // the suffix is stable and predictable for the suggested names. |
1383 names.sort(); | 1373 names.sort(); |
1384 return names.join(); | 1374 return names.join(); |
1385 } | 1375 } |
1386 | 1376 |
1387 /// Property name used for `getInterceptor` or one of its specializations. | 1377 /// Property name used for `getInterceptor` or one of its specializations. |
1388 jsAst.Name nameForGetInterceptor(Iterable<ClassEntity> classes) { | 1378 jsAst.Name nameForGetInterceptor(Iterable<ClassEntity> classes) { |
1389 MethodElement getInterceptor = helpers.getInterceptorMethod; | 1379 MethodElement getInterceptor = _helpers.getInterceptorMethod; |
1390 if (classes.contains(helpers.jsInterceptorClass)) { | 1380 if (classes.contains(_helpers.jsInterceptorClass)) { |
1391 // If the base Interceptor class is in the set of intercepted classes, we | 1381 // If the base Interceptor class is in the set of intercepted classes, we |
1392 // need to go through the generic getInterceptorMethod, since any subclass | 1382 // need to go through the generic getInterceptorMethod, since any subclass |
1393 // of the base Interceptor could match. | 1383 // of the base Interceptor could match. |
1394 // The unspecialized getInterceptor method can also be accessed through | 1384 // The unspecialized getInterceptor method can also be accessed through |
1395 // its element, so we treat this as a user-space global instead of an | 1385 // its element, so we treat this as a user-space global instead of an |
1396 // internal global. | 1386 // internal global. |
1397 return _disambiguateGlobal(getInterceptor); | 1387 return _disambiguateGlobal(getInterceptor); |
1398 } | 1388 } |
1399 String suffix = suffixForGetInterceptor(classes); | 1389 String suffix = suffixForGetInterceptor(classes); |
1400 return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix"); | 1390 return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix"); |
1401 } | 1391 } |
1402 | 1392 |
1403 /// Property name used for the one-shot interceptor method for the given | 1393 /// Property name used for the one-shot interceptor method for the given |
1404 /// [selector] and return-type specialization. | 1394 /// [selector] and return-type specialization. |
1405 jsAst.Name nameForGetOneShotInterceptor( | 1395 jsAst.Name nameForGetOneShotInterceptor( |
1406 Selector selector, Iterable<ClassEntity> classes) { | 1396 Selector selector, Iterable<ClassEntity> classes) { |
1407 // The one-shot name is a global name derived from the invocation name. To | 1397 // The one-shot name is a global name derived from the invocation name. To |
1408 // avoid instability we would like the names to be unique and not clash with | 1398 // avoid instability we would like the names to be unique and not clash with |
1409 // other global names. | 1399 // other global names. |
1410 jsAst.Name root = invocationName(selector); | 1400 jsAst.Name root = invocationName(selector); |
1411 | 1401 |
1412 if (classes.contains(helpers.jsInterceptorClass)) { | 1402 if (classes.contains(_helpers.jsInterceptorClass)) { |
1413 // If the base Interceptor class is in the set of intercepted classes, | 1403 // If the base Interceptor class is in the set of intercepted classes, |
1414 // this is the most general specialization which uses the generic | 1404 // this is the most general specialization which uses the generic |
1415 // getInterceptor method. | 1405 // getInterceptor method. |
1416 // TODO(sra): Find a way to get the simple name when Object is not in the | 1406 // TODO(sra): Find a way to get the simple name when Object is not in the |
1417 // set of classes for most general variant, e.g. "$lt$n" could be "$lt". | 1407 // set of classes for most general variant, e.g. "$lt$n" could be "$lt". |
1418 return new CompoundName([root, _literalDollar]); | 1408 return new CompoundName([root, _literalDollar]); |
1419 } else { | 1409 } else { |
1420 String suffix = suffixForGetInterceptor(classes); | 1410 String suffix = suffixForGetInterceptor(classes); |
1421 return new CompoundName( | 1411 return new CompoundName( |
1422 [root, _literalDollar, new StringBackedName(suffix)]); | 1412 [root, _literalDollar, new StringBackedName(suffix)]); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1522 globalObjectFor(element); | 1512 globalObjectFor(element); |
1523 | 1513 |
1524 /// Returns [staticStateHolder] or one of [reservedGlobalObjectNames]. | 1514 /// Returns [staticStateHolder] or one of [reservedGlobalObjectNames]. |
1525 String globalObjectFor(Element element) { | 1515 String globalObjectFor(Element element) { |
1526 if (_isPropertyOfStaticStateHolder(element)) return staticStateHolder; | 1516 if (_isPropertyOfStaticStateHolder(element)) return staticStateHolder; |
1527 return globalObjectForLibrary(element.library); | 1517 return globalObjectForLibrary(element.library); |
1528 } | 1518 } |
1529 | 1519 |
1530 /// Returns the [reservedGlobalObjectNames] for [library]. | 1520 /// Returns the [reservedGlobalObjectNames] for [library]. |
1531 String globalObjectForLibrary(LibraryElement library) { | 1521 String globalObjectForLibrary(LibraryElement library) { |
1532 if (library == helpers.interceptorsLibrary) return 'J'; | 1522 if (library == _helpers.interceptorsLibrary) return 'J'; |
1533 if (library.isInternalLibrary) return 'H'; | 1523 if (library.isInternalLibrary) return 'H'; |
1534 if (library.isPlatformLibrary) { | 1524 if (library.isPlatformLibrary) { |
1535 if ('${library.canonicalUri}' == 'dart:html') return 'W'; | 1525 if ('${library.canonicalUri}' == 'dart:html') return 'W'; |
1536 return 'P'; | 1526 return 'P'; |
1537 } | 1527 } |
1538 return userGlobalObjects[library.name.hashCode % userGlobalObjects.length]; | 1528 return userGlobalObjects[library.name.hashCode % userGlobalObjects.length]; |
1539 } | 1529 } |
1540 | 1530 |
1541 jsAst.Name deriveLazyInitializerName(jsAst.Name name) { | 1531 jsAst.Name deriveLazyInitializerName(jsAst.Name name) { |
1542 // These are not real dart getters, so do not use GetterName; | 1532 // These are not real dart getters, so do not use GetterName; |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1742 * EventKeyProvider_keyup // const EventKeyProvider('keyup') | 1732 * EventKeyProvider_keyup // const EventKeyProvider('keyup') |
1743 * | 1733 * |
1744 */ | 1734 */ |
1745 class ConstantNamingVisitor implements ConstantValueVisitor { | 1735 class ConstantNamingVisitor implements ConstantValueVisitor { |
1746 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); | 1736 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); |
1747 static const MAX_FRAGMENTS = 5; | 1737 static const MAX_FRAGMENTS = 5; |
1748 static const MAX_EXTRA_LENGTH = 30; | 1738 static const MAX_EXTRA_LENGTH = 30; |
1749 static const DEFAULT_TAG_LENGTH = 3; | 1739 static const DEFAULT_TAG_LENGTH = 3; |
1750 | 1740 |
1751 final RuntimeTypesEncoder rtiEncoder; | 1741 final RuntimeTypesEncoder rtiEncoder; |
1752 final DiagnosticReporter reporter; | |
1753 final CodegenWorldBuilder codegenWorldBuilder; | 1742 final CodegenWorldBuilder codegenWorldBuilder; |
1754 final ConstantCanonicalHasher hasher; | 1743 final ConstantCanonicalHasher hasher; |
1755 | 1744 |
1756 String root = null; // First word, usually a type name. | 1745 String root = null; // First word, usually a type name. |
1757 bool failed = false; // Failed to generate something pretty. | 1746 bool failed = false; // Failed to generate something pretty. |
1758 List<String> fragments = <String>[]; | 1747 List<String> fragments = <String>[]; |
1759 int length = 0; | 1748 int length = 0; |
1760 | 1749 |
1761 ConstantNamingVisitor( | 1750 ConstantNamingVisitor(this.rtiEncoder, this.codegenWorldBuilder, this.hasher); |
1762 this.rtiEncoder, this.reporter, this.codegenWorldBuilder, this.hasher); | |
1763 | 1751 |
1764 String getName(ConstantValue constant) { | 1752 String getName(ConstantValue constant) { |
1765 _visit(constant); | 1753 _visit(constant); |
1766 if (root == null) return 'CONSTANT'; | 1754 if (root == null) return 'CONSTANT'; |
1767 if (failed) return '${root}_${getHashTag(constant, DEFAULT_TAG_LENGTH)}'; | 1755 if (failed) return '${root}_${getHashTag(constant, DEFAULT_TAG_LENGTH)}'; |
1768 if (fragments.length == 1) return 'C_${root}'; | 1756 if (fragments.length == 1) return 'C_${root}'; |
1769 return fragments.join('_'); | 1757 return fragments.join('_'); |
1770 } | 1758 } |
1771 | 1759 |
1772 String getHashTag(ConstantValue constant, int width) => | 1760 String getHashTag(ConstantValue constant, int width) => |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1923 case SyntheticConstantKind.DUMMY_INTERCEPTOR: | 1911 case SyntheticConstantKind.DUMMY_INTERCEPTOR: |
1924 add('dummy_receiver'); | 1912 add('dummy_receiver'); |
1925 break; | 1913 break; |
1926 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: | 1914 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: |
1927 // Omit. These are opaque deferred indexes with nothing helpful to add. | 1915 // Omit. These are opaque deferred indexes with nothing helpful to add. |
1928 break; | 1916 break; |
1929 case SyntheticConstantKind.NAME: | 1917 case SyntheticConstantKind.NAME: |
1930 add('name'); | 1918 add('name'); |
1931 break; | 1919 break; |
1932 default: | 1920 default: |
1933 reporter.internalError( | 1921 throw new SpannableAssertionFailure( |
1934 CURRENT_ELEMENT_SPANNABLE, "Unexpected SyntheticConstantValue"); | 1922 CURRENT_ELEMENT_SPANNABLE, "Unexpected SyntheticConstantValue"); |
1935 } | 1923 } |
1936 } | 1924 } |
1937 | 1925 |
1938 @override | 1926 @override |
1939 void visitDeferred(DeferredConstantValue constant, [_]) { | 1927 void visitDeferred(DeferredConstantValue constant, [_]) { |
1940 addRoot('Deferred'); | 1928 addRoot('Deferred'); |
1941 } | 1929 } |
1942 } | 1930 } |
1943 | 1931 |
1944 /** | 1932 /** |
1945 * Generates canonical hash values for [ConstantValue]s. | 1933 * Generates canonical hash values for [ConstantValue]s. |
1946 * | 1934 * |
1947 * Unfortunately, [Constant.hashCode] is not stable under minor perturbations, | 1935 * Unfortunately, [Constant.hashCode] is not stable under minor perturbations, |
1948 * so it can't be used for generating names. This hasher keeps consistency | 1936 * so it can't be used for generating names. This hasher keeps consistency |
1949 * between runs by basing hash values of the names of elements, rather than | 1937 * between runs by basing hash values of the names of elements, rather than |
1950 * their hashCodes. | 1938 * their hashCodes. |
1951 */ | 1939 */ |
1952 class ConstantCanonicalHasher implements ConstantValueVisitor<int, Null> { | 1940 class ConstantCanonicalHasher implements ConstantValueVisitor<int, Null> { |
1953 static const _MASK = 0x1fffffff; | 1941 static const _MASK = 0x1fffffff; |
1954 static const _UINT32_LIMIT = 4 * 1024 * 1024 * 1024; | 1942 static const _UINT32_LIMIT = 4 * 1024 * 1024 * 1024; |
1955 | 1943 |
1956 final DiagnosticReporter reporter; | |
1957 final RuntimeTypesEncoder rtiEncoder; | 1944 final RuntimeTypesEncoder rtiEncoder; |
1958 final CodegenWorldBuilder codegenWorldBuilder; | 1945 final CodegenWorldBuilder codegenWorldBuilder; |
1959 final Map<ConstantValue, int> hashes = new Map<ConstantValue, int>(); | 1946 final Map<ConstantValue, int> hashes = new Map<ConstantValue, int>(); |
1960 | 1947 |
1961 ConstantCanonicalHasher( | 1948 ConstantCanonicalHasher(this.rtiEncoder, this.codegenWorldBuilder); |
1962 this.rtiEncoder, this.reporter, this.codegenWorldBuilder); | |
1963 | 1949 |
1964 int getHash(ConstantValue constant) => _visit(constant); | 1950 int getHash(ConstantValue constant) => _visit(constant); |
1965 | 1951 |
1966 int _visit(ConstantValue constant) { | 1952 int _visit(ConstantValue constant) { |
1967 int hash = hashes[constant]; | 1953 int hash = hashes[constant]; |
1968 if (hash == null) { | 1954 if (hash == null) { |
1969 hash = _finish(constant.accept(this, null)); | 1955 hash = _finish(constant.accept(this, null)); |
1970 hashes[constant] = hash; | 1956 hashes[constant] = hash; |
1971 } | 1957 } |
1972 return hash; | 1958 return hash; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2040 | 2026 |
2041 @override | 2027 @override |
2042 int visitSynthetic(SyntheticConstantValue constant, [_]) { | 2028 int visitSynthetic(SyntheticConstantValue constant, [_]) { |
2043 switch (constant.valueKind) { | 2029 switch (constant.valueKind) { |
2044 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: | 2030 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: |
2045 // These contain a deferred opaque index into metadata. There is nothing | 2031 // These contain a deferred opaque index into metadata. There is nothing |
2046 // we can access that is stable between compiles. Luckily, since they | 2032 // we can access that is stable between compiles. Luckily, since they |
2047 // resolve to integer indexes, they're always part of a larger constant. | 2033 // resolve to integer indexes, they're always part of a larger constant. |
2048 return 0; | 2034 return 0; |
2049 default: | 2035 default: |
2050 reporter.internalError( | 2036 throw new SpannableAssertionFailure( |
2051 NO_LOCATION_SPANNABLE, | 2037 NO_LOCATION_SPANNABLE, |
2052 'SyntheticConstantValue should never be named and ' | 2038 'SyntheticConstantValue should never be named and ' |
2053 'never be subconstant'); | 2039 'never be subconstant'); |
2054 return 0; | |
2055 } | 2040 } |
2056 } | 2041 } |
2057 | 2042 |
2058 @override | 2043 @override |
2059 int visitDeferred(DeferredConstantValue constant, [_]) { | 2044 int visitDeferred(DeferredConstantValue constant, [_]) { |
2060 // TODO(sra): Investigate that the use of hashCode here is probably a source | 2045 // TODO(sra): Investigate that the use of hashCode here is probably a source |
2061 // of instability. | 2046 // of instability. |
2062 int hash = constant.prefix.hashCode; | 2047 int hash = constant.prefix.hashCode; |
2063 return _combine(hash, _visit(constant.referenced)); | 2048 return _combine(hash, _visit(constant.referenced)); |
2064 } | 2049 } |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2207 void addSuggestion(String original, String suggestion) { | 2192 void addSuggestion(String original, String suggestion) { |
2208 assert(!_suggestedNames.containsKey(original)); | 2193 assert(!_suggestedNames.containsKey(original)); |
2209 _suggestedNames[original] = suggestion; | 2194 _suggestedNames[original] = suggestion; |
2210 } | 2195 } |
2211 | 2196 |
2212 bool hasSuggestion(String original) => _suggestedNames.containsKey(original); | 2197 bool hasSuggestion(String original) => _suggestedNames.containsKey(original); |
2213 bool isSuggestion(String candidate) { | 2198 bool isSuggestion(String candidate) { |
2214 return _suggestedNames.containsValue(candidate); | 2199 return _suggestedNames.containsValue(candidate); |
2215 } | 2200 } |
2216 } | 2201 } |
OLD | NEW |