Index: pkg/compiler/lib/src/js_backend/frequency_namer.dart |
diff --git a/pkg/compiler/lib/src/js_backend/frequency_namer.dart b/pkg/compiler/lib/src/js_backend/frequency_namer.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0aaf8f6703737c9e5bf4d06f6f67cb8124f96b31 |
--- /dev/null |
+++ b/pkg/compiler/lib/src/js_backend/frequency_namer.dart |
@@ -0,0 +1,142 @@ |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
+// for details. All rights reserved. Use of this source code is governed by a |
+// BSD-style license that can be found in the LICENSE file. |
+ |
+part of js_backend; |
+ |
+class FrequencyBasedNamer extends Namer with _MinifiedFieldNamer, |
+ _MinifiedOneShotInterceptorNamer implements jsAst.TokenFinalizer { |
+ _FieldNamingRegistry fieldRegistry; |
+ List<TokenName> tokens = new List<TokenName>(); |
+ |
+ Map<NamingScope, TokenScope> _tokenScopes = |
+ new Maplet<NamingScope, TokenScope>(); |
+ |
+ // Some basic settings for smaller names |
+ String get isolateName => 'I'; |
+ String get isolatePropertiesName => 'p'; |
+ bool get shouldMinify => true; |
+ |
+ final String getterPrefix = 'g'; |
+ final String setterPrefix = 's'; |
+ final String callPrefix = ''; // this will create function names $<n> |
+ |
+ FrequencyBasedNamer(Compiler compiler) : super(compiler) { |
+ fieldRegistry = new _FieldNamingRegistry(this); |
+ } |
+ |
+ TokenScope newScopeFor(NamingScope scope) { |
+ if (scope == NamingScope.instance) { |
+ Set<String> illegalNames = new Set<String>.from(jsReserved); |
+ for (String illegal in MinifyNamer._reservedNativeProperties) { |
+ illegalNames.add(illegal); |
+ if (MinifyNamer._hasBannedPrefix(illegal)) { |
+ illegalNames.add(illegal.substring(1)); |
+ } |
+ } |
+ return new TokenScope(illegalNames); |
+ } else { |
+ return new TokenScope(jsReserved); |
+ } |
+ } |
+ |
+ @override |
+ jsAst.Name getFreshName(NamingScope scope, String proposedName, |
+ {bool sanitizeForNatives: false, |
+ bool sanitizeForAnnotations: false}) { |
+ // Grab the scope for this token |
+ TokenScope tokenScope = _tokenScopes.putIfAbsent(scope, |
+ () => newScopeFor(scope)); |
+ |
+ // Get the name the normal namer would use as a key. |
+ String proposed = _generateFreshStringForName(proposedName, |
+ getUsedNames(scope), |
+ getSuggestedNames(scope), |
+ sanitizeForNatives: |
+ sanitizeForNatives, |
+ sanitizeForAnnotations: |
+ sanitizeForAnnotations); |
+ |
+ TokenName name = new TokenName(tokenScope, proposed); |
+ tokens.add(name); |
+ return name; |
+ } |
+ |
+ @override |
+ jsAst.Name instanceFieldPropertyName(Element element) { |
+ jsAst.Name proposed = _minifiedInstanceFieldPropertyName(element); |
+ if (proposed != null) { |
+ return proposed; |
+ } |
+ return super.instanceFieldPropertyName(element); |
+ } |
+ |
+ @override |
+ void finalizeTokens() { |
+ int compareReferenceCount(TokenName a, TokenName b) { |
+ int result = b._rc - a._rc; |
+ if (result == 0) result = a.key.compareTo(b.key); |
+ return result; |
+ } |
+ |
+ List<TokenName> usedNames = |
+ tokens.where((TokenName a) => a._rc > 0).toList(); |
+ usedNames.sort(compareReferenceCount); |
+ usedNames.forEach((TokenName token) => token.finalize()); |
+ } |
+} |
+ |
+class TokenScope { |
+ List<int> _nextName = [$a]; |
+ final Set<String> illegalNames; |
+ |
+ TokenScope([this.illegalNames = const ImmutableEmptySet()]); |
+ |
+ /// Increments the letter at [pos] in the current name. Also takes care of |
+ /// overflows to the left. Returns the carry bit, i.e., it returns `true` |
+ /// if all positions to the left have wrapped around. |
+ /// |
+ /// If [_nextName] is initially 'a', this will generate the sequence |
+ /// |
+ /// [a-zA-Z] |
+ /// [a-zA-Z][_0-9a-zA-Z] |
+ /// [a-zA-Z][_0-9a-zA-Z][_0-9a-zA-Z] |
+ /// ... |
+ bool _incrementPosition(int pos) { |
+ bool overflow = false; |
+ if (pos < 0) return true; |
+ int value = _nextName[pos]; |
+ if (value == $_) { |
+ value = $0; |
+ } else if (value == $9) { |
+ value = $a; |
+ } else if (value == $z) { |
+ value = $A; |
+ } else if (value == $Z) { |
+ overflow = _incrementPosition(pos - 1); |
+ value = (pos > 0) ? $_ : $a; |
+ } else { |
+ value++; |
+ } |
+ _nextName[pos] = value; |
+ return overflow; |
+ } |
+ |
+ _incrementName() { |
+ if (_incrementPosition(_nextName.length - 1)) { |
+ _nextName.add($_); |
+ } |
+ } |
+ |
+ String getNextName() { |
+ String proposal; |
+ do { |
+ proposal = new String.fromCharCodes(_nextName); |
+ _incrementName(); |
+ } while (MinifyNamer._hasBannedPrefix(proposal) || |
+ illegalNames.contains(proposal)); |
+ |
+ return proposal; |
+ } |
+} |
+ |