| 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 |