Chromium Code Reviews| 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 part of js_backend; | 5 part of js_backend; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Assigns JavaScript identifiers to Dart variables, class-names and members. | 8 * Assigns JavaScript identifiers to Dart variables, class-names and members. |
| 9 * | 9 * |
| 10 * Names are generated through three stages: | 10 * Names are generated through three stages: |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); | 363 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); |
| 364 | 364 |
| 365 final Compiler compiler; | 365 final Compiler compiler; |
| 366 | 366 |
| 367 /// Used disambiguated names in the global namespace, issued by | 367 /// Used disambiguated names in the global namespace, issued by |
| 368 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. | 368 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. |
| 369 /// | 369 /// |
| 370 /// Although global names are distributed across a number of global objects, | 370 /// Although global names are distributed across a number of global objects, |
| 371 /// (see [globalObjectFor]), we currently use a single namespace for all these | 371 /// (see [globalObjectFor]), we currently use a single namespace for all these |
| 372 /// names. | 372 /// names. |
| 373 final Set<String> usedGlobalNames = new Set<String>(); | 373 final NamingScope globalScope = new NamingScope(); |
| 374 final Map<Element, jsAst.Name> userGlobals = | 374 final Map<Element, jsAst.Name> userGlobals = |
| 375 new HashMap<Element, jsAst.Name>(); | 375 new HashMap<Element, jsAst.Name>(); |
| 376 final Map<String, jsAst.Name> internalGlobals = | 376 final Map<String, jsAst.Name> internalGlobals = |
| 377 new HashMap<String, jsAst.Name>(); | 377 new HashMap<String, jsAst.Name>(); |
| 378 | 378 |
| 379 /// Used disambiguated names in the instance namespace, issued by | 379 /// Used disambiguated names in the instance namespace, issued by |
| 380 /// [_disambiguateMember], [_disambiguateInternalMember], | 380 /// [_disambiguateMember], [_disambiguateInternalMember], |
| 381 /// [_disambiguateOperator], and [reservePublicMemberName]. | 381 /// [_disambiguateOperator], and [reservePublicMemberName]. |
| 382 final Set<String> usedInstanceNames = new Set<String>(); | 382 final NamingScope instanceScope = new NamingScope(); |
| 383 final Map<String, jsAst.Name> userInstanceMembers = | 383 final Map<String, jsAst.Name> userInstanceMembers = |
| 384 new HashMap<String, jsAst.Name>(); | 384 new HashMap<String, jsAst.Name>(); |
| 385 final Map<Element, jsAst.Name> internalInstanceMembers = | 385 final Map<Element, jsAst.Name> internalInstanceMembers = |
| 386 new HashMap<Element, jsAst.Name>(); | 386 new HashMap<Element, jsAst.Name>(); |
| 387 final Map<String, jsAst.Name> userInstanceOperators = | 387 final Map<String, jsAst.Name> userInstanceOperators = |
| 388 new HashMap<String, jsAst.Name>(); | 388 new HashMap<String, jsAst.Name>(); |
| 389 | 389 |
| 390 /// Used to disambiguate names for constants in [constantName]. | 390 /// Used to disambiguate names for constants in [constantName]. |
| 391 final Set<String> usedConstantNames = new Set<String>(); | 391 final NamingScope constantScope = new NamingScope(); |
| 392 | |
| 393 Set<String> getUsedNames(NamingScope scope) { | |
| 394 if (scope == NamingScope.global) { | |
| 395 return usedGlobalNames; | |
| 396 } else if (scope == NamingScope.instance){ | |
| 397 return usedInstanceNames; | |
| 398 } else { | |
| 399 assert(scope == NamingScope.constant); | |
| 400 return usedConstantNames; | |
| 401 } | |
| 402 } | |
| 403 | 392 |
| 404 final Map<String, int> popularNameCounters = <String, int>{}; | 393 final Map<String, int> popularNameCounters = <String, int>{}; |
| 405 | 394 |
| 406 final Map<LibraryElement, String> libraryLongNames = | 395 final Map<LibraryElement, String> libraryLongNames = |
| 407 new HashMap<LibraryElement, String>(); | 396 new HashMap<LibraryElement, String>(); |
| 408 | 397 |
| 409 final Map<ConstantValue, jsAst.Name> constantNames = | 398 final Map<ConstantValue, jsAst.Name> constantNames = |
| 410 new HashMap<ConstantValue, jsAst.Name>(); | 399 new HashMap<ConstantValue, jsAst.Name>(); |
| 411 final Map<ConstantValue, String> constantLongNames = | 400 final Map<ConstantValue, String> constantLongNames = |
| 412 <ConstantValue, String>{}; | 401 <ConstantValue, String>{}; |
| 413 ConstantCanonicalHasher constantHasher; | 402 ConstantCanonicalHasher constantHasher; |
| 414 | 403 |
| 415 /// Maps private names to a library that may use that name without prefixing | 404 /// Maps private names to a library that may use that name without prefixing |
| 416 /// itself. Used for building proposed names. | 405 /// itself. Used for building proposed names. |
| 417 final Map<String, LibraryElement> shortPrivateNameOwners = | 406 final Map<String, LibraryElement> shortPrivateNameOwners = |
| 418 <String, LibraryElement>{}; | 407 <String, LibraryElement>{}; |
| 419 | 408 |
| 420 /// Maps proposed names to *suggested* disambiguated names. | 409 |
| 421 /// | |
| 422 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific | |
| 423 /// names be given to the first item with the given proposed name. | |
| 424 /// | |
| 425 /// This is currently used in [MinifyNamer] to assign very short minified | |
| 426 /// names to things that tend to be used very often. | |
| 427 final Map<String, String> suggestedGlobalNames = <String, String>{}; | 410 final Map<String, String> suggestedGlobalNames = <String, String>{}; |
| 428 final Map<String, String> suggestedInstanceNames = <String, String>{}; | 411 final Map<String, String> suggestedInstanceNames = <String, String>{}; |
| 429 | 412 |
| 430 Map<String, String> getSuggestedNames(NamingScope scope) { | |
| 431 if (scope == NamingScope.global) { | |
| 432 return suggestedGlobalNames; | |
| 433 } else if (scope == NamingScope.instance) { | |
| 434 return suggestedInstanceNames; | |
| 435 } else { | |
| 436 assert(scope == NamingScope.constant); | |
| 437 return const {}; | |
| 438 } | |
| 439 } | |
| 440 | |
| 441 | 413 |
| 442 /// Used to store unique keys for library names. Keys are not used as names, | 414 /// Used to store unique keys for library names. Keys are not used as names, |
| 443 /// nor are they visible in the output. The only serve as an internal | 415 /// nor are they visible in the output. The only serve as an internal |
| 444 /// key into maps. | 416 /// key into maps. |
| 445 final Map<LibraryElement, String> _libraryKeys = | 417 final Map<LibraryElement, String> _libraryKeys = |
| 446 new HashMap<LibraryElement, String>(); | 418 new HashMap<LibraryElement, String>(); |
| 447 | 419 |
| 448 Namer(Compiler compiler) | 420 Namer(Compiler compiler) |
| 449 : compiler = compiler, | 421 : compiler = compiler, |
| 450 constantHasher = new ConstantCanonicalHasher(compiler), | 422 constantHasher = new ConstantCanonicalHasher(compiler), |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 538 /// | 510 /// |
| 539 /// Unique within the global-member namespace. | 511 /// Unique within the global-member namespace. |
| 540 jsAst.Name constantName(ConstantValue constant) { | 512 jsAst.Name constantName(ConstantValue constant) { |
| 541 // In the current implementation it doesn't make sense to give names to | 513 // In the current implementation it doesn't make sense to give names to |
| 542 // function constants since the function-implementation itself serves as | 514 // function constants since the function-implementation itself serves as |
| 543 // constant and can be accessed directly. | 515 // constant and can be accessed directly. |
| 544 assert(!constant.isFunction); | 516 assert(!constant.isFunction); |
| 545 jsAst.Name result = constantNames[constant]; | 517 jsAst.Name result = constantNames[constant]; |
| 546 if (result == null) { | 518 if (result == null) { |
| 547 String longName = constantLongName(constant); | 519 String longName = constantLongName(constant); |
| 548 result = getFreshName(NamingScope.constant, longName); | 520 result = getFreshName(constantScope, longName); |
| 549 constantNames[constant] = result; | 521 constantNames[constant] = result; |
| 550 } | 522 } |
| 551 return _newReference(result); | 523 return _newReference(result); |
| 552 } | 524 } |
| 553 | 525 |
| 554 /// Proposed name for [constant]. | 526 /// Proposed name for [constant]. |
| 555 String constantLongName(ConstantValue constant) { | 527 String constantLongName(ConstantValue constant) { |
| 556 String longName = constantLongNames[constant]; | 528 String longName = constantLongNames[constant]; |
| 557 if (longName == null) { | 529 if (longName == null) { |
| 558 longName = new ConstantNamingVisitor(compiler, constantHasher) | 530 longName = new ConstantNamingVisitor(compiler, constantHasher) |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 792 /** | 764 /** |
| 793 * Returns the JavaScript property name used to store an instance field. | 765 * Returns the JavaScript property name used to store an instance field. |
| 794 */ | 766 */ |
| 795 jsAst.Name instanceFieldPropertyName(FieldElement element) { | 767 jsAst.Name instanceFieldPropertyName(FieldElement element) { |
| 796 ClassElement enclosingClass = element.enclosingClass; | 768 ClassElement enclosingClass = element.enclosingClass; |
| 797 | 769 |
| 798 if (backend.hasFixedBackendName(element)) { | 770 if (backend.hasFixedBackendName(element)) { |
| 799 return new StringBackedName(backend.getFixedBackendName(element)); | 771 return new StringBackedName(backend.getFixedBackendName(element)); |
| 800 } | 772 } |
| 801 | 773 |
| 802 // Instances of BoxFieldElement are special. They are already created with | 774 // Some elements, like e.g. instances of BoxFieldElement are special. |
| 803 // a unique and safe name. However, as boxes are not really instances of | 775 // They are created with a unique and safe name for the element model. |
| 804 // classes, the usual naming scheme that tries to avoid name clashes with | 776 // While their name is unique, it is not very readable. So we try to |
| 805 // super classes does not apply. We still do not mark the name as a | 777 // preserve the original, proposed name. |
| 806 // fixedBackendName, as we want to allow other namers to do something more | 778 // However, as boxes are not really instances of classes, the usual naming |
| 807 // clever with them. | 779 // scheme that tries to avoid name clashes with super classes does not |
| 808 if (element is BoxFieldElement) { | 780 // apply. So we can directly grab a name. |
| 809 return new StringBackedName(element.name); | 781 if (element is NameProposingEntity) { |
|
sra1
2015/11/04 02:27:49
Are the names generated here going to be stable?
T
herhut
2015/11/04 15:25:48
This is typically the order in which the model is
| |
| 782 var proposing = entity; | |
|
Siggi Cherem (dart-lang)
2015/11/03 17:21:34
remove this extra var? with the spec's type propag
sra1
2015/11/04 02:27:48
What Siggi says.
'entity' is not in scope.
Had to
herhut
2015/11/04 15:25:48
Sorry, last minute editing change.
herhut
2015/11/04 15:25:48
Did not work for me but with the new hierarchy it
| |
| 783 return _disambiguateInternalMember(element, proposing.proposeName); | |
|
Siggi Cherem (dart-lang)
2015/11/03 17:21:34
(related to my other comment, I'd assume the only
herhut
2015/11/04 15:25:48
It would have been, now I need to create a little
| |
| 810 } | 784 } |
| 811 | 785 |
| 812 // If the name of the field might clash with another field, | 786 // If the name of the field might clash with another field, |
| 813 // use a mangled field name to avoid potential clashes. | 787 // use a mangled field name to avoid potential clashes. |
| 814 // Note that if the class extends a native class, that native class might | 788 // Note that if the class extends a native class, that native class might |
| 815 // have fields with fixed backend names, so we assume the worst and always | 789 // have fields with fixed backend names, so we assume the worst and always |
| 816 // mangle the field names of classes extending native classes. | 790 // mangle the field names of classes extending native classes. |
| 817 // Methods on such classes are stored on the interceptor, not the instance, | 791 // Methods on such classes are stored on the interceptor, not the instance, |
| 818 // so only fields have the potential to clash with a native property name. | 792 // so only fields have the potential to clash with a native property name. |
| 819 ClassWorld classWorld = compiler.world; | 793 ClassWorld classWorld = compiler.world; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 875 jsAst.Name disambiguatedName = _disambiguateMember(originalName); | 849 jsAst.Name disambiguatedName = _disambiguateMember(originalName); |
| 876 return deriveGetterName(disambiguatedName); | 850 return deriveGetterName(disambiguatedName); |
| 877 } | 851 } |
| 878 | 852 |
| 879 /// Disambiguated name for a compiler-owned global variable. | 853 /// Disambiguated name for a compiler-owned global variable. |
| 880 /// | 854 /// |
| 881 /// The resulting name is unique within the global-member namespace. | 855 /// The resulting name is unique within the global-member namespace. |
| 882 jsAst.Name _disambiguateInternalGlobal(String name) { | 856 jsAst.Name _disambiguateInternalGlobal(String name) { |
| 883 jsAst.Name newName = internalGlobals[name]; | 857 jsAst.Name newName = internalGlobals[name]; |
| 884 if (newName == null) { | 858 if (newName == null) { |
| 885 newName = getFreshName(NamingScope.global, name); | 859 newName = getFreshName(globalScope, name); |
| 886 internalGlobals[name] = newName; | 860 internalGlobals[name] = newName; |
| 887 } | 861 } |
| 888 return _newReference(newName); | 862 return _newReference(newName); |
| 889 } | 863 } |
| 890 | 864 |
| 891 /// Returns the property name to use for a compiler-owner global variable, | 865 /// Returns the property name to use for a compiler-owner global variable, |
| 892 /// i.e. one that does not correspond to any element but is used as a utility | 866 /// i.e. one that does not correspond to any element but is used as a utility |
| 893 /// global by code generation. | 867 /// global by code generation. |
| 894 /// | 868 /// |
| 895 /// [name] functions as both the proposed name for the global, and as a key | 869 /// [name] functions as both the proposed name for the global, and as a key |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 922 /// Returns the disambiguated name for a top-level or static element. | 896 /// Returns the disambiguated name for a top-level or static element. |
| 923 /// | 897 /// |
| 924 /// The resulting name is unique within the global-member namespace. | 898 /// The resulting name is unique within the global-member namespace. |
| 925 jsAst.Name _disambiguateGlobal(Element element) { | 899 jsAst.Name _disambiguateGlobal(Element element) { |
| 926 // TODO(asgerf): We can reuse more short names if we disambiguate with | 900 // TODO(asgerf): We can reuse more short names if we disambiguate with |
| 927 // a separate namespace for each of the global holder objects. | 901 // a separate namespace for each of the global holder objects. |
| 928 element = element.declaration; | 902 element = element.declaration; |
| 929 jsAst.Name newName = userGlobals[element]; | 903 jsAst.Name newName = userGlobals[element]; |
| 930 if (newName == null) { | 904 if (newName == null) { |
| 931 String proposedName = _proposeNameForGlobal(element); | 905 String proposedName = _proposeNameForGlobal(element); |
| 932 newName = getFreshName(NamingScope.global, proposedName); | 906 newName = getFreshName(globalScope, proposedName); |
| 933 userGlobals[element] = newName; | 907 userGlobals[element] = newName; |
| 934 } | 908 } |
| 935 return _newReference(newName); | 909 return _newReference(newName); |
| 936 } | 910 } |
| 937 | 911 |
| 938 /// Returns the disambiguated name for an instance method or field | 912 /// Returns the disambiguated name for an instance method or field |
| 939 /// with [originalName] in [library]. | 913 /// with [originalName] in [library]. |
| 940 /// | 914 /// |
| 941 /// [library] may be `null` if [originalName] is known to be public. | 915 /// [library] may be `null` if [originalName] is known to be public. |
| 942 /// | 916 /// |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 962 // This avoids clashes since the original names cannot contain that symbol. | 936 // This avoids clashes since the original names cannot contain that symbol. |
| 963 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; | 937 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; |
| 964 jsAst.Name newName = userInstanceMembers[key]; | 938 jsAst.Name newName = userInstanceMembers[key]; |
| 965 if (newName == null) { | 939 if (newName == null) { |
| 966 String proposedName = privateName(originalName); | 940 String proposedName = privateName(originalName); |
| 967 if (!suffixes.isEmpty) { | 941 if (!suffixes.isEmpty) { |
| 968 // In the proposed name, separate the name parts by '$', because the | 942 // In the proposed name, separate the name parts by '$', because the |
| 969 // proposed name must be a valid identifier, but not necessarily unique. | 943 // proposed name must be a valid identifier, but not necessarily unique. |
| 970 proposedName += r'$' + suffixes.join(r'$'); | 944 proposedName += r'$' + suffixes.join(r'$'); |
| 971 } | 945 } |
| 972 newName = getFreshName(NamingScope.instance, proposedName, | 946 newName = getFreshName(instanceScope, proposedName, |
| 973 sanitizeForAnnotations: true); | 947 sanitizeForAnnotations: true); |
| 974 userInstanceMembers[key] = newName; | 948 userInstanceMembers[key] = newName; |
| 975 } | 949 } |
| 976 return _newReference(newName); | 950 return _newReference(newName); |
| 977 } | 951 } |
| 978 | 952 |
| 979 /// Returns the disambiguated name for the instance member identified by | 953 /// Returns the disambiguated name for the instance member identified by |
| 980 /// [key]. | 954 /// [key]. |
| 981 /// | 955 /// |
| 982 /// When a name for an element is requested by key, it may not be requested | 956 /// When a name for an element is requested by key, it may not be requested |
| 983 /// by element at the same time, as two different names would be returned. | 957 /// by element at the same time, as two different names would be returned. |
| 984 /// | 958 /// |
| 985 /// If key has not yet been registered, [proposeName] is used to generate | 959 /// If key has not yet been registered, [proposeName] is used to generate |
| 986 /// a name proposal for the given key. | 960 /// a name proposal for the given key. |
| 987 /// | 961 /// |
| 988 /// [key] must not clash with valid instance names. This is typically | 962 /// [key] must not clash with valid instance names. This is typically |
| 989 /// achieved by using at least one character in [key] that is not valid in | 963 /// achieved by using at least one character in [key] that is not valid in |
| 990 /// identifiers, for example the @ symbol. | 964 /// identifiers, for example the @ symbol. |
| 991 jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) { | 965 jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) { |
| 992 jsAst.Name newName = userInstanceMembers[key]; | 966 jsAst.Name newName = userInstanceMembers[key]; |
| 993 if (newName == null) { | 967 if (newName == null) { |
| 994 String name = proposeName(); | 968 String name = proposeName(); |
| 995 newName = getFreshName(NamingScope.instance, name, | 969 newName = getFreshName(instanceScope, name, |
| 996 sanitizeForAnnotations: true); | 970 sanitizeForAnnotations: true); |
| 997 userInstanceMembers[key] = newName; | 971 userInstanceMembers[key] = newName; |
| 998 } | 972 } |
| 999 return _newReference(newName); | 973 return _newReference(newName); |
| 1000 } | 974 } |
| 1001 | 975 |
| 1002 /// Forces the public instance member with [originalName] to have the given | 976 /// Forces the public instance member with [originalName] to have the given |
| 1003 /// [disambiguatedName]. | 977 /// [disambiguatedName]. |
| 1004 /// | 978 /// |
| 1005 /// The [originalName] must not have been disambiguated before, and the | 979 /// The [originalName] must not have been disambiguated before, and the |
| 1006 /// [disambiguatedName] must not have been used. | 980 /// [disambiguatedName] must not have been used. |
| 1007 /// | 981 /// |
| 1008 /// Using [_disambiguateMember] with the given [originalName] and no suffixes | 982 /// Using [_disambiguateMember] with the given [originalName] and no suffixes |
| 1009 /// will subsequently return [disambiguatedName]. | 983 /// will subsequently return [disambiguatedName]. |
| 1010 void reservePublicMemberName(String originalName, | 984 void reservePublicMemberName(String originalName, |
| 1011 String disambiguatedName) { | 985 String disambiguatedName) { |
| 1012 // Build a key that corresponds to the one built in disambiguateMember. | 986 // Build a key that corresponds to the one built in disambiguateMember. |
| 1013 String libraryPrefix = ''; // Public names have an empty library prefix. | 987 String libraryPrefix = ''; // Public names have an empty library prefix. |
| 1014 String suffix = ''; // We don't need any suffixes. | 988 String suffix = ''; // We don't need any suffixes. |
| 1015 String key = '$libraryPrefix@$originalName@$suffix'; | 989 String key = '$libraryPrefix@$originalName@$suffix'; |
| 1016 assert(!userInstanceMembers.containsKey(key)); | 990 assert(!userInstanceMembers.containsKey(key)); |
| 1017 assert(!usedInstanceNames.contains(disambiguatedName)); | 991 assert(!instanceScope.isUsed(disambiguatedName)); |
| 1018 userInstanceMembers[key] = new StringBackedName(disambiguatedName); | 992 userInstanceMembers[key] = new StringBackedName(disambiguatedName); |
| 1019 usedInstanceNames.add(disambiguatedName); | 993 instanceScope.registerUse(disambiguatedName); |
| 1020 } | 994 } |
| 1021 | 995 |
| 1022 /// Disambiguated name unique to [element]. | 996 /// Disambiguated name unique to [element]. |
| 1023 /// | 997 /// |
| 1024 /// This is used as the property name for fields, type variables, | 998 /// This is used as the property name for fields, type variables, |
| 1025 /// constructor bodies, and super-accessors. | 999 /// constructor bodies, and super-accessors. |
| 1026 /// | 1000 /// |
| 1027 /// The resulting name is unique within the instance-member namespace. | 1001 /// The resulting name is unique within the instance-member namespace. |
| 1028 jsAst.Name _disambiguateInternalMember(Element element, | 1002 jsAst.Name _disambiguateInternalMember(Element element, |
| 1029 String proposeName()) { | 1003 String proposeName()) { |
| 1030 jsAst.Name newName = internalInstanceMembers[element]; | 1004 jsAst.Name newName = internalInstanceMembers[element]; |
| 1031 if (newName == null) { | 1005 if (newName == null) { |
| 1032 String name = proposeName(); | 1006 String name = proposeName(); |
| 1033 bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass); | 1007 |
| 1034 newName = getFreshName(NamingScope.instance, name, | 1008 if (element is ScopeBearingEntity) { |
| 1035 sanitizeForAnnotations: true, | 1009 var scopeProvider = element; |
|
sra1
2015/11/04 02:27:49
Don't use var to avoid static type checks.
herhut
2015/11/04 15:25:48
Done.
| |
| 1036 sanitizeForNatives: mayClashNative); | 1010 newName = getFreshName(scopeProvider.namingScope, name, |
| 1037 internalInstanceMembers[element] = newName; | 1011 sanitizeForAnnotations: true, |
| 1012 sanitizeForNatives: false); | |
| 1013 internalInstanceMembers[element] = newName; | |
| 1014 } else { | |
| 1015 bool mayClashNative = | |
| 1016 _isUserClassExtendingNative(element.enclosingClass); | |
| 1017 newName = getFreshName(instanceScope, name, | |
| 1018 sanitizeForAnnotations: true, | |
| 1019 sanitizeForNatives: mayClashNative); | |
| 1020 internalInstanceMembers[element] = newName; | |
| 1021 } | |
| 1038 } | 1022 } |
| 1039 return _newReference(newName); | 1023 return _newReference(newName); |
| 1040 } | 1024 } |
| 1041 | 1025 |
| 1042 /// Disambiguated name for the given operator. | 1026 /// Disambiguated name for the given operator. |
| 1043 /// | 1027 /// |
| 1044 /// [operatorIdentifier] must be the operator's identifier, e.g. | 1028 /// [operatorIdentifier] must be the operator's identifier, e.g. |
| 1045 /// `$add` and not `+`. | 1029 /// `$add` and not `+`. |
| 1046 /// | 1030 /// |
| 1047 /// The resulting name is unique within the instance-member namespace. | 1031 /// The resulting name is unique within the instance-member namespace. |
| 1048 jsAst.Name _disambiguateOperator(String operatorIdentifier) { | 1032 jsAst.Name _disambiguateOperator(String operatorIdentifier) { |
| 1049 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; | 1033 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; |
| 1050 if (newName == null) { | 1034 if (newName == null) { |
| 1051 newName = getFreshName(NamingScope.instance, operatorIdentifier); | 1035 newName = getFreshName(instanceScope, operatorIdentifier); |
| 1052 userInstanceOperators[operatorIdentifier] = newName; | 1036 userInstanceOperators[operatorIdentifier] = newName; |
| 1053 } | 1037 } |
| 1054 return _newReference(newName); | 1038 return _newReference(newName); |
| 1055 } | 1039 } |
| 1056 | 1040 |
| 1057 String _generateFreshStringForName(String proposedName, | 1041 String _generateFreshStringForName(String proposedName, |
| 1058 Set<String> usedNames, | 1042 NamingScope scope, |
| 1059 Map<String, String> suggestedNames, | |
| 1060 {bool sanitizeForAnnotations: false, | 1043 {bool sanitizeForAnnotations: false, |
| 1061 bool sanitizeForNatives: false}) { | 1044 bool sanitizeForNatives: false}) { |
| 1062 if (sanitizeForAnnotations) { | 1045 if (sanitizeForAnnotations) { |
| 1063 proposedName = _sanitizeForAnnotations(proposedName); | 1046 proposedName = _sanitizeForAnnotations(proposedName); |
| 1064 } | 1047 } |
| 1065 if (sanitizeForNatives) { | 1048 if (sanitizeForNatives) { |
| 1066 proposedName = _sanitizeForNatives(proposedName); | 1049 proposedName = _sanitizeForNatives(proposedName); |
| 1067 } | 1050 } |
| 1068 proposedName = _sanitizeForKeywords(proposedName); | 1051 proposedName = _sanitizeForKeywords(proposedName); |
| 1069 String candidate; | 1052 String candidate; |
| 1070 if (!usedNames.contains(proposedName)) { | 1053 if (scope.isUnused(proposedName)) { |
| 1071 candidate = proposedName; | 1054 candidate = proposedName; |
| 1072 } else { | 1055 } else { |
| 1073 int counter = popularNameCounters[proposedName]; | 1056 int counter = popularNameCounters[proposedName]; |
| 1074 int i = (counter == null) ? 0 : counter; | 1057 int i = (counter == null) ? 0 : counter; |
| 1075 while (usedNames.contains("$proposedName$i")) { | 1058 while (scope.isUsed("$proposedName$i")) { |
| 1076 i++; | 1059 i++; |
| 1077 } | 1060 } |
| 1078 popularNameCounters[proposedName] = i + 1; | 1061 popularNameCounters[proposedName] = i + 1; |
| 1079 candidate = "$proposedName$i"; | 1062 candidate = "$proposedName$i"; |
| 1080 } | 1063 } |
| 1081 usedNames.add(candidate); | 1064 scope.registerUse(candidate); |
| 1082 return candidate; | 1065 return candidate; |
| 1083 } | 1066 } |
| 1084 | 1067 |
| 1085 /// Returns an unused name. | 1068 /// Returns an unused name. |
| 1086 /// | 1069 /// |
| 1087 /// [proposedName] must be a valid JavaScript identifier. | 1070 /// [proposedName] must be a valid JavaScript identifier. |
| 1088 /// | 1071 /// |
| 1089 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not | 1072 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not |
| 1090 /// to have the form of an annotated name. | 1073 /// to have the form of an annotated name. |
| 1091 /// | 1074 /// |
| 1092 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to | 1075 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to |
| 1093 /// clash with a property name on a native object. | 1076 /// clash with a property name on a native object. |
| 1094 /// | 1077 /// |
| 1095 /// Note that [MinifyNamer] overrides this method with one that produces | 1078 /// Note that [MinifyNamer] overrides this method with one that produces |
| 1096 /// minified names. | 1079 /// minified names. |
| 1097 jsAst.Name getFreshName(NamingScope scope, | 1080 jsAst.Name getFreshName(NamingScope scope, |
| 1098 String proposedName, | 1081 String proposedName, |
| 1099 {bool sanitizeForAnnotations: false, | 1082 {bool sanitizeForAnnotations: false, |
| 1100 bool sanitizeForNatives: false}) { | 1083 bool sanitizeForNatives: false}) { |
| 1101 String candidate = | 1084 String candidate = |
| 1102 _generateFreshStringForName(proposedName, | 1085 _generateFreshStringForName(proposedName, |
| 1103 getUsedNames(scope), | 1086 scope, |
| 1104 getSuggestedNames(scope), | |
| 1105 sanitizeForAnnotations: | 1087 sanitizeForAnnotations: |
| 1106 sanitizeForAnnotations, | 1088 sanitizeForAnnotations, |
| 1107 sanitizeForNatives: sanitizeForNatives); | 1089 sanitizeForNatives: sanitizeForNatives); |
| 1108 return new StringBackedName(candidate); | 1090 return new StringBackedName(candidate); |
| 1109 } | 1091 } |
| 1110 | 1092 |
| 1111 /// Returns a variant of [name] that cannot clash with the annotated | 1093 /// Returns a variant of [name] that cannot clash with the annotated |
| 1112 /// version of another name, that is, the resulting name can never be returned | 1094 /// version of another name, that is, the resulting name can never be returned |
| 1113 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], | 1095 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], |
| 1114 /// [operatorIs], or [substitutionName]. | 1096 /// [operatorIs], or [substitutionName]. |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1429 | 1411 |
| 1430 String get functionTypeNamedParametersTag => r'named'; | 1412 String get functionTypeNamedParametersTag => r'named'; |
| 1431 | 1413 |
| 1432 Map<FunctionType, jsAst.Name> functionTypeNameMap = | 1414 Map<FunctionType, jsAst.Name> functionTypeNameMap = |
| 1433 new HashMap<FunctionType, jsAst.Name>(); | 1415 new HashMap<FunctionType, jsAst.Name>(); |
| 1434 final FunctionTypeNamer functionTypeNamer; | 1416 final FunctionTypeNamer functionTypeNamer; |
| 1435 | 1417 |
| 1436 jsAst.Name getFunctionTypeName(FunctionType functionType) { | 1418 jsAst.Name getFunctionTypeName(FunctionType functionType) { |
| 1437 return functionTypeNameMap.putIfAbsent(functionType, () { | 1419 return functionTypeNameMap.putIfAbsent(functionType, () { |
| 1438 String proposedName = functionTypeNamer.computeName(functionType); | 1420 String proposedName = functionTypeNamer.computeName(functionType); |
| 1439 return getFreshName(NamingScope.instance, proposedName); | 1421 return getFreshName(instanceScope, proposedName); |
| 1440 }); | 1422 }); |
| 1441 } | 1423 } |
| 1442 | 1424 |
| 1443 jsAst.Name operatorIsType(DartType type) { | 1425 jsAst.Name operatorIsType(DartType type) { |
| 1444 if (type.isFunctionType) { | 1426 if (type.isFunctionType) { |
| 1445 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. | 1427 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. |
| 1446 return new CompoundName([new StringBackedName(operatorIsPrefix), | 1428 return new CompoundName([new StringBackedName(operatorIsPrefix), |
| 1447 _literalUnderscore, | 1429 _literalUnderscore, |
| 1448 getFunctionTypeName(type)]); | 1430 getFunctionTypeName(type)]); |
| 1449 } | 1431 } |
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1565 | 1547 |
| 1566 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; | 1548 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; |
| 1567 | 1549 |
| 1568 jsAst.Expression get accessIncrementalHelper { | 1550 jsAst.Expression get accessIncrementalHelper { |
| 1569 return js('self.${incrementalHelperName}'); | 1551 return js('self.${incrementalHelperName}'); |
| 1570 } | 1552 } |
| 1571 | 1553 |
| 1572 void forgetElement(Element element) { | 1554 void forgetElement(Element element) { |
| 1573 jsAst.Name globalName = userGlobals[element]; | 1555 jsAst.Name globalName = userGlobals[element]; |
| 1574 invariant(element, globalName != null, message: 'No global name.'); | 1556 invariant(element, globalName != null, message: 'No global name.'); |
| 1575 usedGlobalNames.remove(globalName); | |
| 1576 userGlobals.remove(element); | 1557 userGlobals.remove(element); |
| 1577 } | 1558 } |
| 1578 } | 1559 } |
| 1579 | 1560 |
| 1580 /** | 1561 /** |
| 1581 * Generator of names for [ConstantValue] values. | 1562 * Generator of names for [ConstantValue] values. |
| 1582 * | 1563 * |
| 1583 * The names are stable under perturbations of the source. The name is either a | 1564 * The names are stable under perturbations of the source. The name is either a |
| 1584 * short sequence of words, if this can be found from the constant, or a type | 1565 * short sequence of words, if this can be found from the constant, or a type |
| 1585 * followed by a hash tag. | 1566 * followed by a hash tag. |
| (...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2021 sb.write('_'); | 2002 sb.write('_'); |
| 2022 } | 2003 } |
| 2023 sb.write('_'); | 2004 sb.write('_'); |
| 2024 visit(parameter); | 2005 visit(parameter); |
| 2025 first = true; | 2006 first = true; |
| 2026 } | 2007 } |
| 2027 } | 2008 } |
| 2028 } | 2009 } |
| 2029 } | 2010 } |
| 2030 | 2011 |
| 2031 enum NamingScope { | 2012 abstract class NameProposingEntity implements Entity { |
| 2032 global, | 2013 String proposeName(); |
| 2033 instance, | |
| 2034 constant | |
| 2035 } | 2014 } |
| 2015 | |
| 2016 abstract class ScopeBearingEntity implements Entity { | |
| 2017 NamingScope get namingScope; | |
| 2018 } | |
| 2019 | |
| 2020 class NamingScope { | |
| 2021 /// Maps proposed names to *suggested* disambiguated names. | |
| 2022 /// | |
| 2023 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific | |
| 2024 /// names be given to the first item with the given proposed name. | |
| 2025 /// | |
| 2026 /// This is currently used in [MinifyNamer] to assign very short minified | |
| 2027 /// names to things that tend to be used very often. | |
| 2028 final Map<String, String> _suggestedNames = new Map<String, String>(); | |
| 2029 final Set<String> _usedNames = new Set<String>(); | |
| 2030 | |
| 2031 bool isUsed(String name) => _usedNames.contains(name); | |
| 2032 bool isUnused(String name) => !_usedNames.contains(name); | |
| 2033 bool registerUse(String name) => _usedNames.add(name); | |
| 2034 | |
| 2035 String suggestName(String original) => _suggestedNames[original]; | |
| 2036 void addSuggestion(String original, String suggestion) { | |
| 2037 assert(!_suggestedNames.containsKey(original)); | |
| 2038 _suggestedNames[original] = suggestion; | |
| 2039 } | |
| 2040 bool hasSuggestion(String original) => _suggestedNames.containsKey(original); | |
| 2041 bool isSuggestion(String candidate) { | |
| 2042 return _suggestedNames.containsValue(candidate); | |
| 2043 } | |
| 2044 } | |
| OLD | NEW |