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

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

Issue 723063003: Make better use of one-letter names when minifying. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 class MinifyNamer extends Namer { 10 class MinifyNamer extends Namer {
(...skipping 17 matching lines...) Expand all
28 // counterpart it will never return the proposedName as the new fresh name. 28 // counterpart it will never return the proposedName as the new fresh name.
29 String getFreshName(String proposedName, 29 String getFreshName(String proposedName,
30 Set<String> usedNames, 30 Set<String> usedNames,
31 Map<String, String> suggestedNames, 31 Map<String, String> suggestedNames,
32 {bool ensureSafe: true}) { 32 {bool ensureSafe: true}) {
33 var freshName; 33 var freshName;
34 var suggestion = suggestedNames[proposedName]; 34 var suggestion = suggestedNames[proposedName];
35 if (suggestion != null && !usedNames.contains(suggestion)) { 35 if (suggestion != null && !usedNames.contains(suggestion)) {
36 freshName = suggestion; 36 freshName = suggestion;
37 } else { 37 } else {
38 freshName = _getUnusedName(proposedName, usedNames); 38 freshName = _getUnusedName(proposedName, usedNames,
39 suggestedNames.values);
39 } 40 }
40 usedNames.add(freshName); 41 usedNames.add(freshName);
41 return freshName; 42 return freshName;
42 } 43 }
43 44
44 String getClosureVariableName(String name, int id) { 45 String getClosureVariableName(String name, int id) {
45 if (id < ALPHABET_CHARACTERS) { 46 if (id < ALPHABET_CHARACTERS) {
46 return new String.fromCharCodes([_letterNumber(id)]); 47 return new String.fromCharCodes([_letterNumber(id)]);
47 } 48 }
48 return "${getMappedInstanceName('closure')}_$id"; 49 return "${getMappedInstanceName('closure')}_$id";
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 90
90 // These popular names are present in most programs and deserve 91 // These popular names are present in most programs and deserve
91 // single character minified names. We could determine the popular names 92 // single character minified names. We could determine the popular names
92 // individually per program, but that would mean that the output of the 93 // individually per program, but that would mean that the output of the
93 // minifier was less stable from version to version of the program being 94 // minifier was less stable from version to version of the program being
94 // minified. 95 // minified.
95 _populateSuggestedNames( 96 _populateSuggestedNames(
96 suggestedInstanceNames, 97 suggestedInstanceNames,
97 usedInstanceNames, 98 usedInstanceNames,
98 const <String>[ 99 const <String>[
99 r'$add', r'add$1', r'$and', r'codeUnitAt$1', r'$or', 100 r'$add', r'add$1', r'$and',
101 r'$or',
100 r'current', r'$shr', r'$eq', r'$ne', 102 r'current', r'$shr', r'$eq', r'$ne',
101 r'getPrototypeOf', r'hasOwnProperty', r'$index', r'$indexSet', 103 r'$index', r'$indexSet',
102 r'$isJavaScriptIndexingBehavior', r'$xor', 104 r'$xor', r'clone$0',
103 r'iterator', r'length', r'$lt', r'$gt', r'$le', r'$ge', 105 r'iterator', r'length',
106 r'$lt', r'$gt', r'$le', r'$ge',
104 r'moveNext$0', r'node', r'on', r'$negate', r'push', r'self', 107 r'moveNext$0', r'node', r'on', r'$negate', r'push', r'self',
105 r'start', r'target', r'$shl', r'value', r'width', r'style', 108 r'start', r'target', r'$shl', r'value', r'width', r'style',
106 r'noSuchMethod$1', r'$mul', r'$div', r'$sub', r'$not', r'$mod', 109 r'noSuchMethod$1', r'$mul', r'$div', r'$sub', r'$not', r'$mod',
107 r'$tdiv']); 110 r'$tdiv', r'toString$0']);
108 111
109 _populateSuggestedNames( 112 _populateSuggestedNames(
110 suggestedGlobalNames, 113 suggestedGlobalNames,
111 usedGlobalNames, 114 usedGlobalNames,
112 const <String>[ 115 const <String>[
113 r'Object', 'wrapException', r'$eq', r'S', r'ioore', 116 r'Object', 'wrapException', r'$eq', r'S', r'ioore',
114 r'UnsupportedError$', r'length', r'$sub', 117 r'UnsupportedError$', r'length', r'$sub',
115 r'getInterceptor$JSArrayJSString', r'$add', 118 r'$add', r'$gt', r'$ge', r'$lt', r'$le', r'add',
116 r'$gt', r'$ge', r'$lt', r'$le', r'add', r'getInterceptor$JSNumber', 119 r'iae',
117 r'iterator', r'$index', r'iae', r'getInterceptor$JSArray', 120 r'ArgumentError$', r'BoundClosure', r'Closure', r'StateError$',
118 r'ArgumentError$', r'BoundClosure', r'StateError$', 121 r'getInterceptor', r'max', r'$mul',
119 r'getInterceptor', r'max', r'$mul', r'List_List', r'Map_Map', 122 r'Map', r'Key_Key', r'$div',
120 r'getInterceptor$JSString', r'$div', r'$indexSet', 123 r'List_List$from',
121 r'List_List$from', r'Set_Set$from', r'toString', r'toInt', r'min', 124 r'LinkedHashMap_LinkedHashMap$_empty',
122 r'StringBuffer_StringBuffer', r'contains1', r'WhereIterable$', 125 r'LinkedHashMap_LinkedHashMap$_literal',
126 r'min',
123 r'RangeError$value', r'JSString', r'JSNumber', 127 r'RangeError$value', r'JSString', r'JSNumber',
124 r'JSArray', r'createInvocationMirror' 128 r'JSArray', r'createInvocationMirror', r'String',
129 r'setRuntimeTypeInfo', r'createRuntimeType'
125 ]); 130 ]);
126 } 131 }
127 132
128 void _populateSuggestedNames(Map<String, String> suggestionMap, 133 void _populateSuggestedNames(Map<String, String> suggestionMap,
129 Set<String> used, 134 Set<String> used,
130 List<String> suggestions) { 135 List<String> suggestions) {
131 int c = $a - 1; 136 int c = $a - 1;
132 String letter; 137 String letter;
133 for (String name in suggestions) { 138 for (String name in suggestions) {
134 do { 139 do {
135 assert(c != $Z); 140 assert(c != $Z);
136 c = (c == $z) ? $A : c + 1; 141 c = (c == $z) ? $A : c + 1;
137 letter = new String.fromCharCodes([c]); 142 letter = new String.fromCharCodes([c]);
138 } while (used.contains(letter)); 143 } while (used.contains(letter));
139 assert(suggestionMap[name] == null); 144 assert(suggestionMap[name] == null);
140 suggestionMap[name] = letter; 145 suggestionMap[name] = letter;
141 } 146 }
142 } 147 }
143 148
144 149
145 // This gets a minified name based on a hash of the proposed name. This 150 // This gets a minified name based on a hash of the proposed name. This
146 // is slightly less efficient than just getting the next name in a series, 151 // is slightly less efficient than just getting the next name in a series,
147 // but it means that small changes in the input program will give smallish 152 // but it means that small changes in the input program will give smallish
148 // changes in the output, which can be useful for diffing etc. 153 // changes in the output, which can be useful for diffing etc.
149 String _getUnusedName(String proposedName, Set<String> usedNames) { 154 String _getUnusedName(String proposedName, Set<String> usedNames,
155 Iterable<String> suggestions) {
150 int hash = _calculateHash(proposedName); 156 int hash = _calculateHash(proposedName);
151 // Avoid very small hashes that won't try many names. 157 // Avoid very small hashes that won't try many names.
152 hash = hash < 1000 ? hash * 314159 : hash; // Yes, it's prime. 158 hash = hash < 1000 ? hash * 314159 : hash; // Yes, it's prime.
153 159
154 // Try other n-character names based on the hash. We try one to three 160 // Try other n-character names based on the hash. We try one to three
155 // character identifiers. For each length we try around 10 different names 161 // character identifiers. For each length we try around 10 different names
156 // in a predictable order determined by the proposed name. This is in order 162 // in a predictable order determined by the proposed name. This is in order
157 // to make the renamer stable: small changes in the input should nornally 163 // to make the renamer stable: small changes in the input should nornally
158 // result in relatively small changes in the output. 164 // result in relatively small changes in the output.
159 for (var n = 2; n <= 3; n++) { 165 for (var n = 1; n <= 3; n++) {
160 int h = hash; 166 int h = hash;
161 while (h > 10) { 167 while (h > 10) {
162 var codes = <int>[_letterNumber(h)]; 168 var codes = <int>[_letterNumber(h)];
163 int h2 = h ~/ ALPHABET_CHARACTERS; 169 int h2 = h ~/ ALPHABET_CHARACTERS;
164 for (var i = 1; i < n; i++) { 170 for (var i = 1; i < n; i++) {
165 codes.add(_alphaNumericNumber(h2)); 171 codes.add(_alphaNumericNumber(h2));
166 h2 ~/= ALPHANUMERIC_CHARACTERS; 172 h2 ~/= ALPHANUMERIC_CHARACTERS;
167 } 173 }
168 final candidate = new String.fromCharCodes(codes); 174 final candidate = new String.fromCharCodes(codes);
169 if (!usedNames.contains(candidate) && 175 if (!usedNames.contains(candidate) &&
170 !jsReserved.contains(candidate) && 176 !jsReserved.contains(candidate) &&
171 !_hasBannedPrefix(candidate)) { 177 !_hasBannedPrefix(candidate) &&
178 (n != 1 || !suggestions.contains(candidate))) {
sra1 2014/11/13 23:52:25 Iterable.contains is not particularly fast.
herhut 2014/11/14 08:44:42 I know but it is not called that often. Only for o
172 return candidate; 179 return candidate;
173 } 180 }
174 // Try again with a slightly different hash. After around 10 turns 181 // Try again with a slightly different hash. After around 10 turns
175 // around this loop h is zero and we try a longer name. 182 // around this loop h is zero and we try a longer name.
176 h ~/= 7; 183 h ~/= 7;
177 } 184 }
178 } 185 }
179 186 return _badName(hash, usedNames);
180 // If we can't find a hash based name in the three-letter space, then base
181 // the name on a letter and a counter.
182 var startLetter = new String.fromCharCodes([_letterNumber(hash)]);
183 var i = 0;
184 while (usedNames.contains("$startLetter$i")) {
185 i++;
186 }
187 // We don't need to check for banned prefix because the name is in the form
188 // xnnn, where nnn is a number. There can be no getter or setter called
189 // gnnn since that would imply a numeric field name.
190 return "$startLetter$i";
191 } 187 }
192 188
193 /// Instance members starting with g and s are reserved for getters and 189 /// Instance members starting with g and s are reserved for getters and
194 /// setters. 190 /// setters.
195 bool _hasBannedPrefix(String name) { 191 bool _hasBannedPrefix(String name) {
196 int code = name.codeUnitAt(0); 192 int code = name.codeUnitAt(0);
197 return code == $g || code == $s; 193 return code == $g || code == $s;
198 } 194 }
199 195
200 int _calculateHash(String name) { 196 int _calculateHash(String name) {
201 int h = 0; 197 int h = 0;
202 for (int i = 0; i < name.length; i++) { 198 for (int i = 0; i < name.length; i++) {
203 h += name.codeUnitAt(i); 199 h += name.codeUnitAt(i);
204 h &= 0xffffffff; 200 h &= 0xffffffff;
205 h += h << 10; 201 h += h << 10;
206 h &= 0xffffffff; 202 h &= 0xffffffff;
207 h ^= h >> 6; 203 h ^= h >> 6;
208 h &= 0xffffffff; 204 h &= 0xffffffff;
209 } 205 }
210 return h; 206 return h;
211 } 207 }
212 208
209 /// If we can't find a hash based name in the three-letter space, then base
210 /// the name on a letter and a counter.
211 String _badName(int hash, Set<String> usedNames) {
212 var startLetter = new String.fromCharCodes([_letterNumber(hash)]);
213 var name;
214 var i = 0;
215 do {
216 name = "$startLetter${i++}";
217 } while (usedNames.contains(name));
218 // We don't need to check for banned prefix because the name is in the form
219 // xnnn, where nnn is a number. There can be no getter or setter called
220 // gnnn since that would imply a numeric field name.
221 return name;
222 }
223
213 int _letterNumber(int x) { 224 int _letterNumber(int x) {
214 if (x >= ALPHABET_CHARACTERS) x %= ALPHABET_CHARACTERS; 225 if (x >= ALPHABET_CHARACTERS) x %= ALPHABET_CHARACTERS;
215 if (x < 26) return $a + x; 226 if (x < 26) return $a + x;
216 return $A + x - 26; 227 return $A + x - 26;
217 } 228 }
218 229
219 int _alphaNumericNumber(int x) { 230 int _alphaNumericNumber(int x) {
220 if (x >= ALPHANUMERIC_CHARACTERS) x %= ALPHANUMERIC_CHARACTERS; 231 if (x >= ALPHANUMERIC_CHARACTERS) x %= ALPHANUMERIC_CHARACTERS;
221 if (x < 26) return $a + x; 232 if (x < 26) return $a + x;
222 if (x < 52) return $A + x - 26; 233 if (x < 52) return $A + x - 26;
223 return $0 + x - 52; 234 return $0 + x - 52;
224 } 235 }
225 236
226 } 237 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698