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 | 392 |
393 Set<String> getUsedNames(NamingScope scope) { | 393 /// Used to store scopes for instances of [PrivatelyNamedJsEntity] |
394 if (scope == NamingScope.global) { | 394 final Map<Entity, NamingScope> _privateNamingScopes = |
395 return usedGlobalNames; | 395 new Map<Entity, NamingScope>(); |
396 } else if (scope == NamingScope.instance){ | |
397 return usedInstanceNames; | |
398 } else { | |
399 assert(scope == NamingScope.constant); | |
400 return usedConstantNames; | |
401 } | |
402 } | |
403 | 396 |
404 final Map<String, int> popularNameCounters = <String, int>{}; | 397 final Map<String, int> popularNameCounters = <String, int>{}; |
405 | 398 |
406 final Map<LibraryElement, String> libraryLongNames = | 399 final Map<LibraryElement, String> libraryLongNames = |
407 new HashMap<LibraryElement, String>(); | 400 new HashMap<LibraryElement, String>(); |
408 | 401 |
409 final Map<ConstantValue, jsAst.Name> constantNames = | 402 final Map<ConstantValue, jsAst.Name> constantNames = |
410 new HashMap<ConstantValue, jsAst.Name>(); | 403 new HashMap<ConstantValue, jsAst.Name>(); |
411 final Map<ConstantValue, String> constantLongNames = | 404 final Map<ConstantValue, String> constantLongNames = |
412 <ConstantValue, String>{}; | 405 <ConstantValue, String>{}; |
413 ConstantCanonicalHasher constantHasher; | 406 ConstantCanonicalHasher constantHasher; |
414 | 407 |
415 /// Maps private names to a library that may use that name without prefixing | 408 /// Maps private names to a library that may use that name without prefixing |
416 /// itself. Used for building proposed names. | 409 /// itself. Used for building proposed names. |
417 final Map<String, LibraryElement> shortPrivateNameOwners = | 410 final Map<String, LibraryElement> shortPrivateNameOwners = |
418 <String, LibraryElement>{}; | 411 <String, LibraryElement>{}; |
419 | 412 |
420 /// Maps proposed names to *suggested* disambiguated names. | |
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>{}; | 413 final Map<String, String> suggestedGlobalNames = <String, String>{}; |
428 final Map<String, String> suggestedInstanceNames = <String, String>{}; | 414 final Map<String, String> suggestedInstanceNames = <String, String>{}; |
429 | 415 |
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 | |
442 /// Used to store unique keys for library names. Keys are not used as names, | 416 /// 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 | 417 /// nor are they visible in the output. The only serve as an internal |
444 /// key into maps. | 418 /// key into maps. |
445 final Map<LibraryElement, String> _libraryKeys = | 419 final Map<LibraryElement, String> _libraryKeys = |
446 new HashMap<LibraryElement, String>(); | 420 new HashMap<LibraryElement, String>(); |
447 | 421 |
448 Namer(Compiler compiler) | 422 Namer(Compiler compiler) |
449 : compiler = compiler, | 423 : compiler = compiler, |
450 constantHasher = new ConstantCanonicalHasher(compiler), | 424 constantHasher = new ConstantCanonicalHasher(compiler), |
451 functionTypeNamer = new FunctionTypeNamer(compiler) { | 425 functionTypeNamer = new FunctionTypeNamer(compiler) { |
(...skipping 17 matching lines...) Expand all Loading... |
469 jsAst.Name get noSuchMethodName => invocationName(Selectors.noSuchMethod_); | 443 jsAst.Name get noSuchMethodName => invocationName(Selectors.noSuchMethod_); |
470 | 444 |
471 /** | 445 /** |
472 * Some closures must contain their name. The name is stored in | 446 * Some closures must contain their name. The name is stored in |
473 * [STATIC_CLOSURE_NAME_NAME]. | 447 * [STATIC_CLOSURE_NAME_NAME]. |
474 */ | 448 */ |
475 String get STATIC_CLOSURE_NAME_NAME => r'$name'; | 449 String get STATIC_CLOSURE_NAME_NAME => r'$name'; |
476 String get closureInvocationSelectorName => Identifiers.call; | 450 String get closureInvocationSelectorName => Identifiers.call; |
477 bool get shouldMinify => false; | 451 bool get shouldMinify => false; |
478 | 452 |
| 453 NamingScope _getPrivateScopeFor(PrivatelyNamedJSEntity entity) { |
| 454 return _privateNamingScopes.putIfAbsent(entity.rootOfScope, |
| 455 () => new NamingScope()); |
| 456 } |
| 457 |
479 /// Returns the string that is to be used as the result of a call to | 458 /// Returns the string that is to be used as the result of a call to |
480 /// [JS_GET_NAME] at [node] with argument [name]. | 459 /// [JS_GET_NAME] at [node] with argument [name]. |
481 jsAst.Name getNameForJsGetName(Node node, JsGetName name) { | 460 jsAst.Name getNameForJsGetName(Node node, JsGetName name) { |
482 switch (name) { | 461 switch (name) { |
483 case JsGetName.GETTER_PREFIX: return asName(getterPrefix); | 462 case JsGetName.GETTER_PREFIX: return asName(getterPrefix); |
484 case JsGetName.SETTER_PREFIX: return asName(setterPrefix); | 463 case JsGetName.SETTER_PREFIX: return asName(setterPrefix); |
485 case JsGetName.CALL_PREFIX: return asName(callPrefix); | 464 case JsGetName.CALL_PREFIX: return asName(callPrefix); |
486 case JsGetName.CALL_PREFIX0: return asName('${callPrefix}\$0'); | 465 case JsGetName.CALL_PREFIX0: return asName('${callPrefix}\$0'); |
487 case JsGetName.CALL_PREFIX1: return asName('${callPrefix}\$1'); | 466 case JsGetName.CALL_PREFIX1: return asName('${callPrefix}\$1'); |
488 case JsGetName.CALL_PREFIX2: return asName('${callPrefix}\$2'); | 467 case JsGetName.CALL_PREFIX2: return asName('${callPrefix}\$2'); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 /// | 517 /// |
539 /// Unique within the global-member namespace. | 518 /// Unique within the global-member namespace. |
540 jsAst.Name constantName(ConstantValue constant) { | 519 jsAst.Name constantName(ConstantValue constant) { |
541 // In the current implementation it doesn't make sense to give names to | 520 // In the current implementation it doesn't make sense to give names to |
542 // function constants since the function-implementation itself serves as | 521 // function constants since the function-implementation itself serves as |
543 // constant and can be accessed directly. | 522 // constant and can be accessed directly. |
544 assert(!constant.isFunction); | 523 assert(!constant.isFunction); |
545 jsAst.Name result = constantNames[constant]; | 524 jsAst.Name result = constantNames[constant]; |
546 if (result == null) { | 525 if (result == null) { |
547 String longName = constantLongName(constant); | 526 String longName = constantLongName(constant); |
548 result = getFreshName(NamingScope.constant, longName); | 527 result = getFreshName(constantScope, longName); |
549 constantNames[constant] = result; | 528 constantNames[constant] = result; |
550 } | 529 } |
551 return _newReference(result); | 530 return _newReference(result); |
552 } | 531 } |
553 | 532 |
554 /// Proposed name for [constant]. | 533 /// Proposed name for [constant]. |
555 String constantLongName(ConstantValue constant) { | 534 String constantLongName(ConstantValue constant) { |
556 String longName = constantLongNames[constant]; | 535 String longName = constantLongNames[constant]; |
557 if (longName == null) { | 536 if (longName == null) { |
558 longName = new ConstantNamingVisitor(compiler, constantHasher) | 537 longName = new ConstantNamingVisitor(compiler, constantHasher) |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
792 /** | 771 /** |
793 * Returns the JavaScript property name used to store an instance field. | 772 * Returns the JavaScript property name used to store an instance field. |
794 */ | 773 */ |
795 jsAst.Name instanceFieldPropertyName(FieldElement element) { | 774 jsAst.Name instanceFieldPropertyName(FieldElement element) { |
796 ClassElement enclosingClass = element.enclosingClass; | 775 ClassElement enclosingClass = element.enclosingClass; |
797 | 776 |
798 if (backend.hasFixedBackendName(element)) { | 777 if (backend.hasFixedBackendName(element)) { |
799 return new StringBackedName(backend.getFixedBackendName(element)); | 778 return new StringBackedName(backend.getFixedBackendName(element)); |
800 } | 779 } |
801 | 780 |
802 // Instances of BoxFieldElement are special. They are already created with | 781 // Some elements, like e.g. instances of BoxFieldElement are special. |
803 // a unique and safe name. However, as boxes are not really instances of | 782 // 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 | 783 // 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 | 784 // preserve the original, proposed name. |
806 // fixedBackendName, as we want to allow other namers to do something more | 785 // However, as boxes are not really instances of classes, the usual naming |
807 // clever with them. | 786 // scheme that tries to avoid name clashes with super classes does not |
808 if (element is BoxFieldElement) { | 787 // apply. So we can directly grab a name. |
809 return new StringBackedName(element.name); | 788 if (element is JSEntity) { |
| 789 return _disambiguateInternalMember(element, |
| 790 () => element.declaredEntity.name); |
810 } | 791 } |
811 | 792 |
812 // If the name of the field might clash with another field, | 793 // If the name of the field might clash with another field, |
813 // use a mangled field name to avoid potential clashes. | 794 // use a mangled field name to avoid potential clashes. |
814 // Note that if the class extends a native class, that native class might | 795 // 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 | 796 // have fields with fixed backend names, so we assume the worst and always |
816 // mangle the field names of classes extending native classes. | 797 // mangle the field names of classes extending native classes. |
817 // Methods on such classes are stored on the interceptor, not the instance, | 798 // 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. | 799 // so only fields have the potential to clash with a native property name. |
819 ClassWorld classWorld = compiler.world; | 800 ClassWorld classWorld = compiler.world; |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
875 jsAst.Name disambiguatedName = _disambiguateMember(originalName); | 856 jsAst.Name disambiguatedName = _disambiguateMember(originalName); |
876 return deriveGetterName(disambiguatedName); | 857 return deriveGetterName(disambiguatedName); |
877 } | 858 } |
878 | 859 |
879 /// Disambiguated name for a compiler-owned global variable. | 860 /// Disambiguated name for a compiler-owned global variable. |
880 /// | 861 /// |
881 /// The resulting name is unique within the global-member namespace. | 862 /// The resulting name is unique within the global-member namespace. |
882 jsAst.Name _disambiguateInternalGlobal(String name) { | 863 jsAst.Name _disambiguateInternalGlobal(String name) { |
883 jsAst.Name newName = internalGlobals[name]; | 864 jsAst.Name newName = internalGlobals[name]; |
884 if (newName == null) { | 865 if (newName == null) { |
885 newName = getFreshName(NamingScope.global, name); | 866 newName = getFreshName(globalScope, name); |
886 internalGlobals[name] = newName; | 867 internalGlobals[name] = newName; |
887 } | 868 } |
888 return _newReference(newName); | 869 return _newReference(newName); |
889 } | 870 } |
890 | 871 |
891 /// Returns the property name to use for a compiler-owner global variable, | 872 /// 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 | 873 /// i.e. one that does not correspond to any element but is used as a utility |
893 /// global by code generation. | 874 /// global by code generation. |
894 /// | 875 /// |
895 /// [name] functions as both the proposed name for the global, and as a key | 876 /// [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. | 903 /// Returns the disambiguated name for a top-level or static element. |
923 /// | 904 /// |
924 /// The resulting name is unique within the global-member namespace. | 905 /// The resulting name is unique within the global-member namespace. |
925 jsAst.Name _disambiguateGlobal(Element element) { | 906 jsAst.Name _disambiguateGlobal(Element element) { |
926 // TODO(asgerf): We can reuse more short names if we disambiguate with | 907 // TODO(asgerf): We can reuse more short names if we disambiguate with |
927 // a separate namespace for each of the global holder objects. | 908 // a separate namespace for each of the global holder objects. |
928 element = element.declaration; | 909 element = element.declaration; |
929 jsAst.Name newName = userGlobals[element]; | 910 jsAst.Name newName = userGlobals[element]; |
930 if (newName == null) { | 911 if (newName == null) { |
931 String proposedName = _proposeNameForGlobal(element); | 912 String proposedName = _proposeNameForGlobal(element); |
932 newName = getFreshName(NamingScope.global, proposedName); | 913 newName = getFreshName(globalScope, proposedName); |
933 userGlobals[element] = newName; | 914 userGlobals[element] = newName; |
934 } | 915 } |
935 return _newReference(newName); | 916 return _newReference(newName); |
936 } | 917 } |
937 | 918 |
938 /// Returns the disambiguated name for an instance method or field | 919 /// Returns the disambiguated name for an instance method or field |
939 /// with [originalName] in [library]. | 920 /// with [originalName] in [library]. |
940 /// | 921 /// |
941 /// [library] may be `null` if [originalName] is known to be public. | 922 /// [library] may be `null` if [originalName] is known to be public. |
942 /// | 923 /// |
(...skipping 19 matching lines...) Expand all Loading... |
962 // This avoids clashes since the original names cannot contain that symbol. | 943 // This avoids clashes since the original names cannot contain that symbol. |
963 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; | 944 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; |
964 jsAst.Name newName = userInstanceMembers[key]; | 945 jsAst.Name newName = userInstanceMembers[key]; |
965 if (newName == null) { | 946 if (newName == null) { |
966 String proposedName = privateName(originalName); | 947 String proposedName = privateName(originalName); |
967 if (!suffixes.isEmpty) { | 948 if (!suffixes.isEmpty) { |
968 // In the proposed name, separate the name parts by '$', because the | 949 // In the proposed name, separate the name parts by '$', because the |
969 // proposed name must be a valid identifier, but not necessarily unique. | 950 // proposed name must be a valid identifier, but not necessarily unique. |
970 proposedName += r'$' + suffixes.join(r'$'); | 951 proposedName += r'$' + suffixes.join(r'$'); |
971 } | 952 } |
972 newName = getFreshName(NamingScope.instance, proposedName, | 953 newName = getFreshName(instanceScope, proposedName, |
973 sanitizeForAnnotations: true); | 954 sanitizeForAnnotations: true); |
974 userInstanceMembers[key] = newName; | 955 userInstanceMembers[key] = newName; |
975 } | 956 } |
976 return _newReference(newName); | 957 return _newReference(newName); |
977 } | 958 } |
978 | 959 |
979 /// Returns the disambiguated name for the instance member identified by | 960 /// Returns the disambiguated name for the instance member identified by |
980 /// [key]. | 961 /// [key]. |
981 /// | 962 /// |
982 /// When a name for an element is requested by key, it may not be requested | 963 /// 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. | 964 /// by element at the same time, as two different names would be returned. |
984 /// | 965 /// |
985 /// If key has not yet been registered, [proposeName] is used to generate | 966 /// If key has not yet been registered, [proposeName] is used to generate |
986 /// a name proposal for the given key. | 967 /// a name proposal for the given key. |
987 /// | 968 /// |
988 /// [key] must not clash with valid instance names. This is typically | 969 /// [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 | 970 /// achieved by using at least one character in [key] that is not valid in |
990 /// identifiers, for example the @ symbol. | 971 /// identifiers, for example the @ symbol. |
991 jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) { | 972 jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) { |
992 jsAst.Name newName = userInstanceMembers[key]; | 973 jsAst.Name newName = userInstanceMembers[key]; |
993 if (newName == null) { | 974 if (newName == null) { |
994 String name = proposeName(); | 975 String name = proposeName(); |
995 newName = getFreshName(NamingScope.instance, name, | 976 newName = getFreshName(instanceScope, name, |
996 sanitizeForAnnotations: true); | 977 sanitizeForAnnotations: true); |
997 userInstanceMembers[key] = newName; | 978 userInstanceMembers[key] = newName; |
998 } | 979 } |
999 return _newReference(newName); | 980 return _newReference(newName); |
1000 } | 981 } |
1001 | 982 |
1002 /// Forces the public instance member with [originalName] to have the given | 983 /// Forces the public instance member with [originalName] to have the given |
1003 /// [disambiguatedName]. | 984 /// [disambiguatedName]. |
1004 /// | 985 /// |
1005 /// The [originalName] must not have been disambiguated before, and the | 986 /// The [originalName] must not have been disambiguated before, and the |
1006 /// [disambiguatedName] must not have been used. | 987 /// [disambiguatedName] must not have been used. |
1007 /// | 988 /// |
1008 /// Using [_disambiguateMember] with the given [originalName] and no suffixes | 989 /// Using [_disambiguateMember] with the given [originalName] and no suffixes |
1009 /// will subsequently return [disambiguatedName]. | 990 /// will subsequently return [disambiguatedName]. |
1010 void reservePublicMemberName(String originalName, | 991 void reservePublicMemberName(String originalName, |
1011 String disambiguatedName) { | 992 String disambiguatedName) { |
1012 // Build a key that corresponds to the one built in disambiguateMember. | 993 // Build a key that corresponds to the one built in disambiguateMember. |
1013 String libraryPrefix = ''; // Public names have an empty library prefix. | 994 String libraryPrefix = ''; // Public names have an empty library prefix. |
1014 String suffix = ''; // We don't need any suffixes. | 995 String suffix = ''; // We don't need any suffixes. |
1015 String key = '$libraryPrefix@$originalName@$suffix'; | 996 String key = '$libraryPrefix@$originalName@$suffix'; |
1016 assert(!userInstanceMembers.containsKey(key)); | 997 assert(!userInstanceMembers.containsKey(key)); |
1017 assert(!usedInstanceNames.contains(disambiguatedName)); | 998 assert(!instanceScope.isUsed(disambiguatedName)); |
1018 userInstanceMembers[key] = new StringBackedName(disambiguatedName); | 999 userInstanceMembers[key] = new StringBackedName(disambiguatedName); |
1019 usedInstanceNames.add(disambiguatedName); | 1000 instanceScope.registerUse(disambiguatedName); |
1020 } | 1001 } |
1021 | 1002 |
1022 /// Disambiguated name unique to [element]. | 1003 /// Disambiguated name unique to [element]. |
1023 /// | 1004 /// |
1024 /// This is used as the property name for fields, type variables, | 1005 /// This is used as the property name for fields, type variables, |
1025 /// constructor bodies, and super-accessors. | 1006 /// constructor bodies, and super-accessors. |
1026 /// | 1007 /// |
1027 /// The resulting name is unique within the instance-member namespace. | 1008 /// The resulting name is unique within the instance-member namespace. |
1028 jsAst.Name _disambiguateInternalMember(Element element, | 1009 jsAst.Name _disambiguateInternalMember(Element element, |
1029 String proposeName()) { | 1010 String proposeName()) { |
1030 jsAst.Name newName = internalInstanceMembers[element]; | 1011 jsAst.Name newName = internalInstanceMembers[element]; |
1031 if (newName == null) { | 1012 if (newName == null) { |
1032 String name = proposeName(); | 1013 String name = proposeName(); |
1033 bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass); | 1014 |
1034 newName = getFreshName(NamingScope.instance, name, | 1015 if (element is PrivatelyNamedJSEntity) { |
1035 sanitizeForAnnotations: true, | 1016 NamingScope scope = _getPrivateScopeFor(element); |
1036 sanitizeForNatives: mayClashNative); | 1017 newName = getFreshName(scope, name, |
1037 internalInstanceMembers[element] = newName; | 1018 sanitizeForAnnotations: true, |
| 1019 sanitizeForNatives: false); |
| 1020 internalInstanceMembers[element] = newName; |
| 1021 } else { |
| 1022 bool mayClashNative = |
| 1023 _isUserClassExtendingNative(element.enclosingClass); |
| 1024 newName = getFreshName(instanceScope, name, |
| 1025 sanitizeForAnnotations: true, |
| 1026 sanitizeForNatives: mayClashNative); |
| 1027 internalInstanceMembers[element] = newName; |
| 1028 } |
1038 } | 1029 } |
1039 return _newReference(newName); | 1030 return _newReference(newName); |
1040 } | 1031 } |
1041 | 1032 |
1042 /// Disambiguated name for the given operator. | 1033 /// Disambiguated name for the given operator. |
1043 /// | 1034 /// |
1044 /// [operatorIdentifier] must be the operator's identifier, e.g. | 1035 /// [operatorIdentifier] must be the operator's identifier, e.g. |
1045 /// `$add` and not `+`. | 1036 /// `$add` and not `+`. |
1046 /// | 1037 /// |
1047 /// The resulting name is unique within the instance-member namespace. | 1038 /// The resulting name is unique within the instance-member namespace. |
1048 jsAst.Name _disambiguateOperator(String operatorIdentifier) { | 1039 jsAst.Name _disambiguateOperator(String operatorIdentifier) { |
1049 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; | 1040 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; |
1050 if (newName == null) { | 1041 if (newName == null) { |
1051 newName = getFreshName(NamingScope.instance, operatorIdentifier); | 1042 newName = getFreshName(instanceScope, operatorIdentifier); |
1052 userInstanceOperators[operatorIdentifier] = newName; | 1043 userInstanceOperators[operatorIdentifier] = newName; |
1053 } | 1044 } |
1054 return _newReference(newName); | 1045 return _newReference(newName); |
1055 } | 1046 } |
1056 | 1047 |
1057 String _generateFreshStringForName(String proposedName, | 1048 String _generateFreshStringForName(String proposedName, |
1058 Set<String> usedNames, | 1049 NamingScope scope, |
1059 Map<String, String> suggestedNames, | |
1060 {bool sanitizeForAnnotations: false, | 1050 {bool sanitizeForAnnotations: false, |
1061 bool sanitizeForNatives: false}) { | 1051 bool sanitizeForNatives: false}) { |
1062 if (sanitizeForAnnotations) { | 1052 if (sanitizeForAnnotations) { |
1063 proposedName = _sanitizeForAnnotations(proposedName); | 1053 proposedName = _sanitizeForAnnotations(proposedName); |
1064 } | 1054 } |
1065 if (sanitizeForNatives) { | 1055 if (sanitizeForNatives) { |
1066 proposedName = _sanitizeForNatives(proposedName); | 1056 proposedName = _sanitizeForNatives(proposedName); |
1067 } | 1057 } |
1068 proposedName = _sanitizeForKeywords(proposedName); | 1058 proposedName = _sanitizeForKeywords(proposedName); |
1069 String candidate; | 1059 String candidate; |
1070 if (!usedNames.contains(proposedName)) { | 1060 if (scope.isUnused(proposedName)) { |
1071 candidate = proposedName; | 1061 candidate = proposedName; |
1072 } else { | 1062 } else { |
1073 int counter = popularNameCounters[proposedName]; | 1063 int counter = popularNameCounters[proposedName]; |
1074 int i = (counter == null) ? 0 : counter; | 1064 int i = (counter == null) ? 0 : counter; |
1075 while (usedNames.contains("$proposedName$i")) { | 1065 while (scope.isUsed("$proposedName$i")) { |
1076 i++; | 1066 i++; |
1077 } | 1067 } |
1078 popularNameCounters[proposedName] = i + 1; | 1068 popularNameCounters[proposedName] = i + 1; |
1079 candidate = "$proposedName$i"; | 1069 candidate = "$proposedName$i"; |
1080 } | 1070 } |
1081 usedNames.add(candidate); | 1071 scope.registerUse(candidate); |
1082 return candidate; | 1072 return candidate; |
1083 } | 1073 } |
1084 | 1074 |
1085 /// Returns an unused name. | 1075 /// Returns an unused name. |
1086 /// | 1076 /// |
1087 /// [proposedName] must be a valid JavaScript identifier. | 1077 /// [proposedName] must be a valid JavaScript identifier. |
1088 /// | 1078 /// |
1089 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not | 1079 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not |
1090 /// to have the form of an annotated name. | 1080 /// to have the form of an annotated name. |
1091 /// | 1081 /// |
1092 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to | 1082 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to |
1093 /// clash with a property name on a native object. | 1083 /// clash with a property name on a native object. |
1094 /// | 1084 /// |
1095 /// Note that [MinifyNamer] overrides this method with one that produces | 1085 /// Note that [MinifyNamer] overrides this method with one that produces |
1096 /// minified names. | 1086 /// minified names. |
1097 jsAst.Name getFreshName(NamingScope scope, | 1087 jsAst.Name getFreshName(NamingScope scope, |
1098 String proposedName, | 1088 String proposedName, |
1099 {bool sanitizeForAnnotations: false, | 1089 {bool sanitizeForAnnotations: false, |
1100 bool sanitizeForNatives: false}) { | 1090 bool sanitizeForNatives: false}) { |
1101 String candidate = | 1091 String candidate = |
1102 _generateFreshStringForName(proposedName, | 1092 _generateFreshStringForName(proposedName, |
1103 getUsedNames(scope), | 1093 scope, |
1104 getSuggestedNames(scope), | |
1105 sanitizeForAnnotations: | 1094 sanitizeForAnnotations: |
1106 sanitizeForAnnotations, | 1095 sanitizeForAnnotations, |
1107 sanitizeForNatives: sanitizeForNatives); | 1096 sanitizeForNatives: sanitizeForNatives); |
1108 return new StringBackedName(candidate); | 1097 return new StringBackedName(candidate); |
1109 } | 1098 } |
1110 | 1099 |
1111 /// Returns a variant of [name] that cannot clash with the annotated | 1100 /// 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 | 1101 /// version of another name, that is, the resulting name can never be returned |
1113 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], | 1102 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], |
1114 /// [operatorIs], or [substitutionName]. | 1103 /// [operatorIs], or [substitutionName]. |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1429 | 1418 |
1430 String get functionTypeNamedParametersTag => r'named'; | 1419 String get functionTypeNamedParametersTag => r'named'; |
1431 | 1420 |
1432 Map<FunctionType, jsAst.Name> functionTypeNameMap = | 1421 Map<FunctionType, jsAst.Name> functionTypeNameMap = |
1433 new HashMap<FunctionType, jsAst.Name>(); | 1422 new HashMap<FunctionType, jsAst.Name>(); |
1434 final FunctionTypeNamer functionTypeNamer; | 1423 final FunctionTypeNamer functionTypeNamer; |
1435 | 1424 |
1436 jsAst.Name getFunctionTypeName(FunctionType functionType) { | 1425 jsAst.Name getFunctionTypeName(FunctionType functionType) { |
1437 return functionTypeNameMap.putIfAbsent(functionType, () { | 1426 return functionTypeNameMap.putIfAbsent(functionType, () { |
1438 String proposedName = functionTypeNamer.computeName(functionType); | 1427 String proposedName = functionTypeNamer.computeName(functionType); |
1439 return getFreshName(NamingScope.instance, proposedName); | 1428 return getFreshName(instanceScope, proposedName); |
1440 }); | 1429 }); |
1441 } | 1430 } |
1442 | 1431 |
1443 jsAst.Name operatorIsType(DartType type) { | 1432 jsAst.Name operatorIsType(DartType type) { |
1444 if (type.isFunctionType) { | 1433 if (type.isFunctionType) { |
1445 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. | 1434 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. |
1446 return new CompoundName([new StringBackedName(operatorIsPrefix), | 1435 return new CompoundName([new StringBackedName(operatorIsPrefix), |
1447 _literalUnderscore, | 1436 _literalUnderscore, |
1448 getFunctionTypeName(type)]); | 1437 getFunctionTypeName(type)]); |
1449 } | 1438 } |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1565 | 1554 |
1566 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; | 1555 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; |
1567 | 1556 |
1568 jsAst.Expression get accessIncrementalHelper { | 1557 jsAst.Expression get accessIncrementalHelper { |
1569 return js('self.${incrementalHelperName}'); | 1558 return js('self.${incrementalHelperName}'); |
1570 } | 1559 } |
1571 | 1560 |
1572 void forgetElement(Element element) { | 1561 void forgetElement(Element element) { |
1573 jsAst.Name globalName = userGlobals[element]; | 1562 jsAst.Name globalName = userGlobals[element]; |
1574 invariant(element, globalName != null, message: 'No global name.'); | 1563 invariant(element, globalName != null, message: 'No global name.'); |
1575 usedGlobalNames.remove(globalName); | |
1576 userGlobals.remove(element); | 1564 userGlobals.remove(element); |
1577 } | 1565 } |
1578 } | 1566 } |
1579 | 1567 |
1580 /** | 1568 /** |
1581 * Generator of names for [ConstantValue] values. | 1569 * Generator of names for [ConstantValue] values. |
1582 * | 1570 * |
1583 * The names are stable under perturbations of the source. The name is either a | 1571 * 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 | 1572 * short sequence of words, if this can be found from the constant, or a type |
1585 * followed by a hash tag. | 1573 * followed by a hash tag. |
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2021 sb.write('_'); | 2009 sb.write('_'); |
2022 } | 2010 } |
2023 sb.write('_'); | 2011 sb.write('_'); |
2024 visit(parameter); | 2012 visit(parameter); |
2025 first = true; | 2013 first = true; |
2026 } | 2014 } |
2027 } | 2015 } |
2028 } | 2016 } |
2029 } | 2017 } |
2030 | 2018 |
2031 enum NamingScope { | 2019 |
2032 global, | 2020 class NamingScope { |
2033 instance, | 2021 /// Maps proposed names to *suggested* disambiguated names. |
2034 constant | 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 } |
2035 } | 2044 } |
OLD | NEW |