| 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 |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 | 395 |
| 396 jsAst.Name _rtiFieldName; | 396 jsAst.Name _rtiFieldName; |
| 397 jsAst.Name get rtiFieldName => _rtiFieldName ??= new StringBackedName(r'$ti'); | 397 jsAst.Name get rtiFieldName => _rtiFieldName ??= new StringBackedName(r'$ti'); |
| 398 | 398 |
| 399 // Name of property in a class description for the native dispatch metadata. | 399 // Name of property in a class description for the native dispatch metadata. |
| 400 final String nativeSpecProperty = '%'; | 400 final String nativeSpecProperty = '%'; |
| 401 | 401 |
| 402 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); | 402 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); |
| 403 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); | 403 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); |
| 404 | 404 |
| 405 final Compiler compiler; | 405 final JavaScriptBackend backend; |
| 406 final ClosedWorld closedWorld; |
| 406 | 407 |
| 407 /// Used disambiguated names in the global namespace, issued by | 408 /// Used disambiguated names in the global namespace, issued by |
| 408 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. | 409 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. |
| 409 /// | 410 /// |
| 410 /// Although global names are distributed across a number of global objects, | 411 /// Although global names are distributed across a number of global objects, |
| 411 /// (see [globalObjectFor]), we currently use a single namespace for all these | 412 /// (see [globalObjectFor]), we currently use a single namespace for all these |
| 412 /// names. | 413 /// names. |
| 413 final NamingScope globalScope = new NamingScope(); | 414 final NamingScope globalScope = new NamingScope(); |
| 414 final Map<Element, jsAst.Name> userGlobals = | 415 final Map<Element, jsAst.Name> userGlobals = |
| 415 new HashMap<Element, jsAst.Name>(); | 416 new HashMap<Element, jsAst.Name>(); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 | 453 |
| 453 final Map<String, String> suggestedGlobalNames = <String, String>{}; | 454 final Map<String, String> suggestedGlobalNames = <String, String>{}; |
| 454 final Map<String, String> suggestedInstanceNames = <String, String>{}; | 455 final Map<String, String> suggestedInstanceNames = <String, String>{}; |
| 455 | 456 |
| 456 /// Used to store unique keys for library names. Keys are not used as names, | 457 /// Used to store unique keys for library names. Keys are not used as names, |
| 457 /// nor are they visible in the output. The only serve as an internal | 458 /// nor are they visible in the output. The only serve as an internal |
| 458 /// key into maps. | 459 /// key into maps. |
| 459 final Map<LibraryElement, String> _libraryKeys = | 460 final Map<LibraryElement, String> _libraryKeys = |
| 460 new HashMap<LibraryElement, String>(); | 461 new HashMap<LibraryElement, String>(); |
| 461 | 462 |
| 462 Namer(Compiler compiler) | 463 Namer(JavaScriptBackend backend, this.closedWorld) |
| 463 : compiler = compiler, | 464 : this.backend = backend, |
| 464 constantHasher = new ConstantCanonicalHasher(compiler), | 465 constantHasher = |
| 465 functionTypeNamer = new FunctionTypeNamer(compiler) { | 466 new ConstantCanonicalHasher(backend.rtiEncoder, backend.reporter), |
| 467 functionTypeNamer = new FunctionTypeNamer(backend.rtiEncoder) { |
| 466 _literalAsyncPrefix = new StringBackedName(asyncPrefix); | 468 _literalAsyncPrefix = new StringBackedName(asyncPrefix); |
| 467 _literalGetterPrefix = new StringBackedName(getterPrefix); | 469 _literalGetterPrefix = new StringBackedName(getterPrefix); |
| 468 _literalSetterPrefix = new StringBackedName(setterPrefix); | 470 _literalSetterPrefix = new StringBackedName(setterPrefix); |
| 469 _literalLazyGetterPrefix = new StringBackedName(lazyGetterPrefix); | 471 _literalLazyGetterPrefix = new StringBackedName(lazyGetterPrefix); |
| 470 } | 472 } |
| 471 | 473 |
| 472 JavaScriptBackend get backend => compiler.backend; | |
| 473 | |
| 474 BackendHelpers get helpers => backend.helpers; | 474 BackendHelpers get helpers => backend.helpers; |
| 475 | 475 |
| 476 DiagnosticReporter get reporter => compiler.reporter; | 476 DiagnosticReporter get reporter => backend.reporter; |
| 477 | 477 |
| 478 CoreClasses get coreClasses => compiler.coreClasses; | 478 CoreClasses get coreClasses => closedWorld.coreClasses; |
| 479 | 479 |
| 480 String get deferredTypesName => 'deferredTypes'; | 480 String get deferredTypesName => 'deferredTypes'; |
| 481 String get isolateName => 'Isolate'; | 481 String get isolateName => 'Isolate'; |
| 482 String get isolatePropertiesName => r'$isolateProperties'; | 482 String get isolatePropertiesName => r'$isolateProperties'; |
| 483 jsAst.Name get noSuchMethodName => invocationName(Selectors.noSuchMethod_); | 483 jsAst.Name get noSuchMethodName => invocationName(Selectors.noSuchMethod_); |
| 484 | 484 |
| 485 /** | 485 /** |
| 486 * Some closures must contain their name. The name is stored in | 486 * Some closures must contain their name. The name is stored in |
| 487 * [STATIC_CLOSURE_NAME_NAME]. | 487 * [STATIC_CLOSURE_NAME_NAME]. |
| 488 */ | 488 */ |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 584 result = getFreshName(constantScope, longName); | 584 result = getFreshName(constantScope, longName); |
| 585 constantNames[constant] = result; | 585 constantNames[constant] = result; |
| 586 } | 586 } |
| 587 return _newReference(result); | 587 return _newReference(result); |
| 588 } | 588 } |
| 589 | 589 |
| 590 /// Proposed name for [constant]. | 590 /// Proposed name for [constant]. |
| 591 String constantLongName(ConstantValue constant) { | 591 String constantLongName(ConstantValue constant) { |
| 592 String longName = constantLongNames[constant]; | 592 String longName = constantLongNames[constant]; |
| 593 if (longName == null) { | 593 if (longName == null) { |
| 594 longName = | 594 longName = new ConstantNamingVisitor( |
| 595 new ConstantNamingVisitor(compiler, constantHasher).getName(constant); | 595 backend.rtiEncoder, reporter, constantHasher) |
| 596 .getName(constant); |
| 596 constantLongNames[constant] = longName; | 597 constantLongNames[constant] = longName; |
| 597 } | 598 } |
| 598 return longName; | 599 return longName; |
| 599 } | 600 } |
| 600 | 601 |
| 601 String breakLabelName(LabelDefinition label) { | 602 String breakLabelName(LabelDefinition label) { |
| 602 return '\$${label.labelName}\$${label.target.nestingLevel}'; | 603 return '\$${label.labelName}\$${label.target.nestingLevel}'; |
| 603 } | 604 } |
| 604 | 605 |
| 605 String implicitBreakLabelName(JumpTarget target) { | 606 String implicitBreakLabelName(JumpTarget target) { |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 847 element, () => asEntity.declaredEntity.name); | 848 element, () => asEntity.declaredEntity.name); |
| 848 } | 849 } |
| 849 | 850 |
| 850 // If the name of the field might clash with another field, | 851 // If the name of the field might clash with another field, |
| 851 // use a mangled field name to avoid potential clashes. | 852 // use a mangled field name to avoid potential clashes. |
| 852 // Note that if the class extends a native class, that native class might | 853 // Note that if the class extends a native class, that native class might |
| 853 // have fields with fixed backend names, so we assume the worst and always | 854 // have fields with fixed backend names, so we assume the worst and always |
| 854 // mangle the field names of classes extending native classes. | 855 // mangle the field names of classes extending native classes. |
| 855 // Methods on such classes are stored on the interceptor, not the instance, | 856 // Methods on such classes are stored on the interceptor, not the instance, |
| 856 // so only fields have the potential to clash with a native property name. | 857 // so only fields have the potential to clash with a native property name. |
| 857 ClosedWorld closedWorld = compiler.closedWorld; | |
| 858 if (closedWorld.isUsedAsMixin(enclosingClass) || | 858 if (closedWorld.isUsedAsMixin(enclosingClass) || |
| 859 _isShadowingSuperField(element) || | 859 _isShadowingSuperField(element) || |
| 860 _isUserClassExtendingNative(enclosingClass)) { | 860 _isUserClassExtendingNative(enclosingClass)) { |
| 861 String proposeName() => '${enclosingClass.name}_${element.name}'; | 861 String proposeName() => '${enclosingClass.name}_${element.name}'; |
| 862 return _disambiguateInternalMember(element, proposeName); | 862 return _disambiguateInternalMember(element, proposeName); |
| 863 } | 863 } |
| 864 | 864 |
| 865 // No superclass uses the disambiguated name as a property name, so we can | 865 // No superclass uses the disambiguated name as a property name, so we can |
| 866 // use it for this field. This generates nicer field names since otherwise | 866 // use it for this field. This generates nicer field names since otherwise |
| 867 // the field name would have to be mangled. | 867 // the field name would have to be mangled. |
| (...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1636 * Duration_16000 // const Duration(milliseconds: 16) | 1636 * Duration_16000 // const Duration(milliseconds: 16) |
| 1637 * EventKeyProvider_keyup // const EventKeyProvider('keyup') | 1637 * EventKeyProvider_keyup // const EventKeyProvider('keyup') |
| 1638 * | 1638 * |
| 1639 */ | 1639 */ |
| 1640 class ConstantNamingVisitor implements ConstantValueVisitor { | 1640 class ConstantNamingVisitor implements ConstantValueVisitor { |
| 1641 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); | 1641 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); |
| 1642 static const MAX_FRAGMENTS = 5; | 1642 static const MAX_FRAGMENTS = 5; |
| 1643 static const MAX_EXTRA_LENGTH = 30; | 1643 static const MAX_EXTRA_LENGTH = 30; |
| 1644 static const DEFAULT_TAG_LENGTH = 3; | 1644 static const DEFAULT_TAG_LENGTH = 3; |
| 1645 | 1645 |
| 1646 final Compiler compiler; | 1646 final RuntimeTypesEncoder rtiEncoder; |
| 1647 final DiagnosticReporter reporter; |
| 1647 final ConstantCanonicalHasher hasher; | 1648 final ConstantCanonicalHasher hasher; |
| 1648 | 1649 |
| 1649 String root = null; // First word, usually a type name. | 1650 String root = null; // First word, usually a type name. |
| 1650 bool failed = false; // Failed to generate something pretty. | 1651 bool failed = false; // Failed to generate something pretty. |
| 1651 List<String> fragments = <String>[]; | 1652 List<String> fragments = <String>[]; |
| 1652 int length = 0; | 1653 int length = 0; |
| 1653 | 1654 |
| 1654 ConstantNamingVisitor(this.compiler, this.hasher); | 1655 ConstantNamingVisitor(this.rtiEncoder, this.reporter, this.hasher); |
| 1655 | |
| 1656 DiagnosticReporter get reporter => compiler.reporter; | |
| 1657 | 1656 |
| 1658 String getName(ConstantValue constant) { | 1657 String getName(ConstantValue constant) { |
| 1659 _visit(constant); | 1658 _visit(constant); |
| 1660 if (root == null) return 'CONSTANT'; | 1659 if (root == null) return 'CONSTANT'; |
| 1661 if (failed) return '${root}_${getHashTag(constant, DEFAULT_TAG_LENGTH)}'; | 1660 if (failed) return '${root}_${getHashTag(constant, DEFAULT_TAG_LENGTH)}'; |
| 1662 if (fragments.length == 1) return 'C_${root}'; | 1661 if (fragments.length == 1) return 'C_${root}'; |
| 1663 return fragments.join('_'); | 1662 return fragments.join('_'); |
| 1664 } | 1663 } |
| 1665 | 1664 |
| 1666 String getHashTag(ConstantValue constant, int width) => | 1665 String getHashTag(ConstantValue constant, int width) => |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1790 | 1789 |
| 1791 @override | 1790 @override |
| 1792 void visitType(TypeConstantValue constant, [_]) { | 1791 void visitType(TypeConstantValue constant, [_]) { |
| 1793 // Generates something like 'Type_String_k8F', using the simple name of the | 1792 // Generates something like 'Type_String_k8F', using the simple name of the |
| 1794 // type and a hash to disambiguate the same name in different libraries. | 1793 // type and a hash to disambiguate the same name in different libraries. |
| 1795 addRoot('Type'); | 1794 addRoot('Type'); |
| 1796 DartType type = constant.representedType; | 1795 DartType type = constant.representedType; |
| 1797 String name = type.element?.name; | 1796 String name = type.element?.name; |
| 1798 if (name == null) { | 1797 if (name == null) { |
| 1799 // e.g. DartType 'dynamic' has no element. | 1798 // e.g. DartType 'dynamic' has no element. |
| 1800 JavaScriptBackend backend = compiler.backend; | 1799 name = rtiEncoder.getTypeRepresentationForTypeConstant(type); |
| 1801 name = backend.rtiEncoder.getTypeRepresentationForTypeConstant(type); | |
| 1802 } | 1800 } |
| 1803 addIdentifier(name); | 1801 addIdentifier(name); |
| 1804 add(getHashTag(constant, 3)); | 1802 add(getHashTag(constant, 3)); |
| 1805 } | 1803 } |
| 1806 | 1804 |
| 1807 @override | 1805 @override |
| 1808 void visitInterceptor(InterceptorConstantValue constant, [_]) { | 1806 void visitInterceptor(InterceptorConstantValue constant, [_]) { |
| 1809 addRoot(constant.dispatchedType.element.name); | 1807 addRoot(constant.dispatchedType.element.name); |
| 1810 add('methods'); | 1808 add('methods'); |
| 1811 } | 1809 } |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1839 * | 1837 * |
| 1840 * Unfortunately, [Constant.hashCode] is not stable under minor perturbations, | 1838 * Unfortunately, [Constant.hashCode] is not stable under minor perturbations, |
| 1841 * so it can't be used for generating names. This hasher keeps consistency | 1839 * so it can't be used for generating names. This hasher keeps consistency |
| 1842 * between runs by basing hash values of the names of elements, rather than | 1840 * between runs by basing hash values of the names of elements, rather than |
| 1843 * their hashCodes. | 1841 * their hashCodes. |
| 1844 */ | 1842 */ |
| 1845 class ConstantCanonicalHasher implements ConstantValueVisitor<int, Null> { | 1843 class ConstantCanonicalHasher implements ConstantValueVisitor<int, Null> { |
| 1846 static const _MASK = 0x1fffffff; | 1844 static const _MASK = 0x1fffffff; |
| 1847 static const _UINT32_LIMIT = 4 * 1024 * 1024 * 1024; | 1845 static const _UINT32_LIMIT = 4 * 1024 * 1024 * 1024; |
| 1848 | 1846 |
| 1849 final Compiler compiler; | 1847 final DiagnosticReporter reporter; |
| 1848 final RuntimeTypesEncoder rtiEncoder; |
| 1850 final Map<ConstantValue, int> hashes = new Map<ConstantValue, int>(); | 1849 final Map<ConstantValue, int> hashes = new Map<ConstantValue, int>(); |
| 1851 | 1850 |
| 1852 ConstantCanonicalHasher(this.compiler); | 1851 ConstantCanonicalHasher(this.rtiEncoder, this.reporter); |
| 1853 | |
| 1854 DiagnosticReporter get reporter => compiler.reporter; | |
| 1855 | 1852 |
| 1856 int getHash(ConstantValue constant) => _visit(constant); | 1853 int getHash(ConstantValue constant) => _visit(constant); |
| 1857 | 1854 |
| 1858 int _visit(ConstantValue constant) { | 1855 int _visit(ConstantValue constant) { |
| 1859 int hash = hashes[constant]; | 1856 int hash = hashes[constant]; |
| 1860 if (hash == null) { | 1857 if (hash == null) { |
| 1861 hash = _finish(constant.accept(this, null)); | 1858 hash = _finish(constant.accept(this, null)); |
| 1862 hashes[constant] = hash; | 1859 hashes[constant] = hash; |
| 1863 } | 1860 } |
| 1864 return hash; | 1861 return hash; |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1911 int hash = _hashString(3, constant.type.element.name); | 1908 int hash = _hashString(3, constant.type.element.name); |
| 1912 constant.type.element.forEachInstanceField((_, FieldElement field) { | 1909 constant.type.element.forEachInstanceField((_, FieldElement field) { |
| 1913 hash = _combine(hash, _visit(constant.fields[field])); | 1910 hash = _combine(hash, _visit(constant.fields[field])); |
| 1914 }, includeSuperAndInjectedMembers: true); | 1911 }, includeSuperAndInjectedMembers: true); |
| 1915 return hash; | 1912 return hash; |
| 1916 } | 1913 } |
| 1917 | 1914 |
| 1918 @override | 1915 @override |
| 1919 int visitType(TypeConstantValue constant, [_]) { | 1916 int visitType(TypeConstantValue constant, [_]) { |
| 1920 DartType type = constant.representedType; | 1917 DartType type = constant.representedType; |
| 1921 JavaScriptBackend backend = compiler.backend; | |
| 1922 // This name includes the library name and type parameters. | 1918 // This name includes the library name and type parameters. |
| 1923 String name = backend.rtiEncoder.getTypeRepresentationForTypeConstant(type); | 1919 String name = rtiEncoder.getTypeRepresentationForTypeConstant(type); |
| 1924 return _hashString(4, name); | 1920 return _hashString(4, name); |
| 1925 } | 1921 } |
| 1926 | 1922 |
| 1927 @override | 1923 @override |
| 1928 int visitInterceptor(InterceptorConstantValue constant, [_]) { | 1924 int visitInterceptor(InterceptorConstantValue constant, [_]) { |
| 1929 String typeName = constant.dispatchedType.element.name; | 1925 String typeName = constant.dispatchedType.element.name; |
| 1930 return _hashString(5, typeName); | 1926 return _hashString(5, typeName); |
| 1931 } | 1927 } |
| 1932 | 1928 |
| 1933 @override | 1929 @override |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2020 } | 2016 } |
| 2021 | 2017 |
| 2022 static int _finish(int hash) { | 2018 static int _finish(int hash) { |
| 2023 hash = _MASK & (hash + (((_MASK >> 3) & hash) << 3)); | 2019 hash = _MASK & (hash + (((_MASK >> 3) & hash) << 3)); |
| 2024 hash = hash & (hash >> 11); | 2020 hash = hash & (hash >> 11); |
| 2025 return _MASK & (hash + (((_MASK >> 15) & hash) << 15)); | 2021 return _MASK & (hash + (((_MASK >> 15) & hash) << 15)); |
| 2026 } | 2022 } |
| 2027 } | 2023 } |
| 2028 | 2024 |
| 2029 class FunctionTypeNamer extends BaseDartTypeVisitor { | 2025 class FunctionTypeNamer extends BaseDartTypeVisitor { |
| 2030 final Compiler compiler; | 2026 final RuntimeTypesEncoder rtiEncoder; |
| 2031 StringBuffer sb; | 2027 StringBuffer sb; |
| 2032 | 2028 |
| 2033 FunctionTypeNamer(this.compiler); | 2029 FunctionTypeNamer(this.rtiEncoder); |
| 2034 | |
| 2035 JavaScriptBackend get backend => compiler.backend; | |
| 2036 | 2030 |
| 2037 String computeName(DartType type) { | 2031 String computeName(DartType type) { |
| 2038 sb = new StringBuffer(); | 2032 sb = new StringBuffer(); |
| 2039 visit(type); | 2033 visit(type); |
| 2040 return sb.toString(); | 2034 return sb.toString(); |
| 2041 } | 2035 } |
| 2042 | 2036 |
| 2043 visit(DartType type, [_]) { | 2037 visit(DartType type, [_]) { |
| 2044 type.accept(this, null); | 2038 type.accept(this, null); |
| 2045 } | 2039 } |
| 2046 | 2040 |
| 2047 visitType(DartType type, _) { | 2041 visitType(DartType type, _) { |
| 2048 sb.write(type.name); | 2042 sb.write(type.name); |
| 2049 } | 2043 } |
| 2050 | 2044 |
| 2051 visitFunctionType(FunctionType type, _) { | 2045 visitFunctionType(FunctionType type, _) { |
| 2052 if (backend.rtiEncoder.isSimpleFunctionType(type)) { | 2046 if (rtiEncoder.isSimpleFunctionType(type)) { |
| 2053 sb.write('args${type.parameterTypes.length}'); | 2047 sb.write('args${type.parameterTypes.length}'); |
| 2054 return; | 2048 return; |
| 2055 } | 2049 } |
| 2056 visit(type.returnType); | 2050 visit(type.returnType); |
| 2057 sb.write('_'); | 2051 sb.write('_'); |
| 2058 for (DartType parameter in type.parameterTypes) { | 2052 for (DartType parameter in type.parameterTypes) { |
| 2059 sb.write('_'); | 2053 sb.write('_'); |
| 2060 visit(parameter); | 2054 visit(parameter); |
| 2061 } | 2055 } |
| 2062 bool first = false; | 2056 bool first = false; |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2101 void addSuggestion(String original, String suggestion) { | 2095 void addSuggestion(String original, String suggestion) { |
| 2102 assert(!_suggestedNames.containsKey(original)); | 2096 assert(!_suggestedNames.containsKey(original)); |
| 2103 _suggestedNames[original] = suggestion; | 2097 _suggestedNames[original] = suggestion; |
| 2104 } | 2098 } |
| 2105 | 2099 |
| 2106 bool hasSuggestion(String original) => _suggestedNames.containsKey(original); | 2100 bool hasSuggestion(String original) => _suggestedNames.containsKey(original); |
| 2107 bool isSuggestion(String candidate) { | 2101 bool isSuggestion(String candidate) { |
| 2108 return _suggestedNames.containsValue(candidate); | 2102 return _suggestedNames.containsValue(candidate); |
| 2109 } | 2103 } |
| 2110 } | 2104 } |
| OLD | NEW |