Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(162)

Side by Side Diff: pkg/compiler/lib/src/js_backend/namer.dart

Issue 1428853004: Use better names for captured variables in closures. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Address comments Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « pkg/compiler/lib/src/js_backend/minify_namer.dart ('k') | tests/compiler/dart2js/js_backend_cps_ir_closures_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698