Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart |
| diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..cd0529f26f8f6b9a7e0b5200c74fb3f716fa5601 |
| --- /dev/null |
| +++ b/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart |
| @@ -0,0 +1,111 @@ |
| +// Copyright (c) 2011, 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. |
| + |
| +/** |
| + * Assigns JavaScript identifiers to Dart variables, class-names and members. |
| + */ |
| +class MinifyNamer extends Namer { |
| + MinifyNamer(Compiler compiler) : super(compiler); |
| + |
| + String get ISOLATE => 'I'; |
| + String get ISOLATE_PROPERTIES => 'p'; |
| + bool get shouldMinify => true; |
| + |
| + const ALPHABET_CHARACTERS = 52; // a-zA-Z. |
| + const ALPHANUMERIC_CHARACTERS = 62; // a-zA-Z0-9. |
| + |
| + String getFreshName(String proposedName, Set<String> usedNames) { |
|
floitsch
2012/11/13 13:35:02
Add comment that the proposedName does not need to
erikcorry
2012/11/16 10:08:30
Done.
|
| + var freshName; |
| + if (proposedName.startsWith(r'call$')) { |
|
floitsch
2012/11/13 13:35:02
This won't work if we mangle constantNames. If the
erikcorry
2012/11/16 10:08:30
Good catch. I moved the special handling of the c
|
| + // We don't mangle the closure invoking function name because it is |
| + // generated in applyFunction. |
| + freshName = proposedName; |
| + } else { |
| + freshName = _getUnusedName(proposedName, usedNames); |
| + } |
| + usedNames.add(freshName); |
| + return freshName; |
| + } |
| + |
| + // This gets a minified name based on a hash of the proposed name. This |
| + // is slightly less efficient than just getting the next name in a series, |
| + // but it means that small changes in the input program will give smallish |
| + // changes in the output, which can be useful for diffing etc. |
| + String _getUnusedName(String proposedName, Set<String> usedNames) { |
| + // Try single-character names with characters that occur in the |
| + // input. |
| + for (int i = 0; i < proposedName.length; i++) { |
| + String candidate = proposedName[i]; |
| + int code = candidate.charCodeAt(0); |
| + if (code < $A) continue; |
| + if (code > $z) continue; |
| + if (code > $Z && code < $a) continue; |
| + if (!usedNames.contains(candidate)) return candidate; |
| + } |
| + |
| + int hash = _calculateHash(proposedName); |
| + // Avoid very small hashes that won't try many names. |
| + hash = hash < 1000 ? hash * 314159 : hash; // Yes, it's prime. |
| + |
| + // Try other n-character names based on the hash. We try one to three |
| + // character identifiers. For each length we try around 10 different names |
| + // in a predictable order determined by the proposed name. This is in order |
| + // to make the renamer stable: small changes in the input should nornally |
| + // result in relatively small changes in the output. |
| + for (var n = 1; n <= 3; n++) { |
| + int h = hash; |
| + while (h > 10) { |
| + var codes = <int>[_letterNumber(h)]; |
| + int h2 = h ~/ ALPHABET_CHARACTERS; |
| + for (var i = 1; i < n; i++) { |
| + codes.add(_alphaNumericNumber(h2)); |
| + h2 ~/= ALPHANUMERIC_CHARACTERS; |
| + } |
| + final candidate = new String.fromCharCodes(codes); |
| + if (!usedNames.contains(candidate) && !jsReserved.contains(candidate)) { |
| + return candidate; |
| + } |
| + // Try again with a slightly different hash. After around 10 turns |
| + // around this loop h is zero and we try a longer name. |
| + h ~/= 7; |
| + } |
| + } |
| + |
| + // If we can't find a hash based name in the three-letter space, then base |
| + // the name on a letter and a counter. |
| + proposedName = new String.fromCharCodes([_letterNumber(hash)]); |
| + var i = 0; |
| + while (usedNames.contains("$proposedName$i")) { |
| + i++; |
| + } |
| + return "$proposedName$i"; |
| + } |
| + |
| + int _calculateHash(String name) { |
| + int h = 0; |
| + for (int i = 0; i < name.length; i++) { |
| + h += name.charCodeAt(i); |
| + h &= 0xffffffff; |
| + h += h << 10; |
| + h &= 0xffffffff; |
| + h ^= h >> 6; |
| + h &= 0xffffffff; |
| + } |
| + return h; |
| + } |
| + |
| + int _letterNumber(int x) { |
| + if (x >= ALPHABET_CHARACTERS) x %= ALPHABET_CHARACTERS; |
| + if (x < 26) return $a + x; |
| + return $A + x - 26; |
| + } |
| + |
| + int _alphaNumericNumber(int x) { |
| + if (x >= ALPHANUMERIC_CHARACTERS) x %= ALPHANUMERIC_CHARACTERS; |
| + if (x < 26) return $a + x; |
| + if (x < 52) return $A + x - 26; |
| + return $0 + x - 52; |
| + } |
| + |
| +} |