OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 part of dart_backend; | |
6 | |
7 Comparator get _compareNodes => | |
8 compareBy((n) => n.getBeginToken().charOffset); | |
9 | |
10 abstract class Renamable implements Comparable { | |
11 final int RENAMABLE_TYPE_ELEMENT = 1; | |
12 final int RENAMABLE_TYPE_MEMBER = 2; | |
13 final int RENAMABLE_TYPE_LOCAL = 3; | |
14 | |
15 final Set<Node> nodes; | |
16 | |
17 Renamable(this.nodes); | |
18 int compareTo(Renamable other) { | |
19 int nodesDiff = other.nodes.length.compareTo(this.nodes.length); | |
20 if (nodesDiff != 0) return nodesDiff; | |
21 int typeDiff = this.kind.compareTo(other.kind); | |
22 return typeDiff != 0 ? typeDiff : compareInternals(other); | |
23 } | |
24 | |
25 int compareInternals(Renamable other); | |
26 int get kind; | |
27 | |
28 String createNewName(PlaceholderRenamer placeholderRenamer); | |
29 } | |
30 | |
31 class GlobalRenamable extends Renamable { | |
32 final Entity entity; | |
33 | |
34 GlobalRenamable(this.entity, Set<Node> nodes) | |
35 : super(nodes); | |
36 | |
37 int compareInternals(GlobalRenamable other) => | |
38 compareElements(this.entity, other.entity); | |
39 int get kind => RENAMABLE_TYPE_ELEMENT; | |
40 String createNewName(PlaceholderRenamer placeholderRenamer) { | |
41 return placeholderRenamer._renameGlobal(entity); | |
42 } | |
43 } | |
44 | |
45 class MemberRenamable extends Renamable { | |
46 final String identifier; | |
47 MemberRenamable(this.identifier, Set<Node> nodes) | |
48 : super(nodes); | |
49 int compareInternals(MemberRenamable other) => | |
50 this.identifier.compareTo(other.identifier); | |
51 int get kind => RENAMABLE_TYPE_MEMBER; | |
52 String createNewName(PlaceholderRenamer placeholderRenamer) { | |
53 return placeholderRenamer._generateMemberName(identifier); | |
54 } | |
55 } | |
56 | |
57 class LocalRenamable extends Renamable { | |
58 LocalRenamable(Set<Node> nodes) | |
59 : super(nodes); | |
60 int compareInternals(LocalRenamable other) => | |
61 _compareNodes(sorted(this.nodes, _compareNodes)[0], | |
62 sorted(other.nodes, _compareNodes)[0]); | |
63 int get kind => RENAMABLE_TYPE_LOCAL; | |
64 String createNewName(PlaceholderRenamer placeholderRenamer) { | |
65 return placeholderRenamer._generateUniqueTopLevelName(""); | |
66 } | |
67 } | |
68 | |
69 /** | |
70 * Renames only top-level elements that would lead to ambiguity if not renamed. | |
71 */ | |
72 class PlaceholderRenamer { | |
73 /// After running [computeRenames] this will contain the computed renames. | |
74 final Map<Node, String> renames = new Map<Node, String>(); | |
75 /// After running [computeRenames] this will contain the used platform | |
76 /// libraries. | |
77 final Set<LibraryElement> platformImports = new Set<LibraryElement>(); | |
78 | |
79 final bool enableMinification; | |
80 final Set<String> fixedMemberNames; | |
81 final Map<Element, LibraryElement> reexportingLibraries; | |
82 final bool cutDeclarationTypes; | |
83 | |
84 final Map<Entity, String> _renamedCache = new Map<Entity, String>(); | |
85 final Map<Entity, Map<String, String>> _privateCache = | |
86 new Map<Entity, Map<String, String>>(); | |
87 | |
88 // Identifiers that has already been used, or are reserved by the | |
89 // language/platform. | |
90 Set<String> _forbiddenIdentifiers; | |
91 Set<String> _allNamedParameterIdentifiers; | |
92 | |
93 Generator _generator; | |
94 | |
95 PlaceholderRenamer(this.fixedMemberNames, | |
96 this.reexportingLibraries, | |
97 {this.enableMinification, this.cutDeclarationTypes}); | |
98 | |
99 void _renameNodes(Iterable<Node> nodes, String renamer(Node node)) { | |
100 for (Node node in sorted(nodes, _compareNodes)) { | |
101 renames[node] = renamer(node); | |
102 } | |
103 } | |
104 | |
105 String _generateUniqueTopLevelName(originalName) { | |
106 String newName = _generator.generate(originalName, (name) { | |
107 return _forbiddenIdentifiers.contains(name) || | |
108 _allNamedParameterIdentifiers.contains(name); | |
109 }); | |
110 _forbiddenIdentifiers.add(newName); | |
111 return newName; | |
112 } | |
113 | |
114 String _generateMemberName(String original) { | |
115 return _generator.generate(original, _forbiddenIdentifiers.contains); | |
116 } | |
117 | |
118 /// Looks up [originalName] in the [_privateCache] cache of [library]. | |
119 /// If [originalName] was not renamed before, generate a new name. | |
120 String _getPrivateName(LibraryElement library, String originalName) { | |
121 return _privateCache.putIfAbsent(library, () => new Map<String, String>()) | |
122 .putIfAbsent(originalName, | |
123 () => _generateUniqueTopLevelName(originalName)); | |
124 } | |
125 | |
126 String _renameConstructor(ConstructorPlaceholder placeholder) { | |
127 String name = placeholder.element.name; | |
128 if (name == '') return ""; | |
129 String result = _renameGlobal(placeholder.element); | |
130 return result; | |
131 } | |
132 | |
133 String _renameGlobal(Entity entity) { | |
134 assert(entity is! Element || | |
135 Elements.isErroneousElement(entity) || | |
136 Elements.isStaticOrTopLevel(entity) || | |
137 entity is TypeVariableElement); | |
138 // TODO(smok): We may want to reuse class static field and method names. | |
139 if (entity is Element) { | |
140 LibraryElement library = entity.library; | |
141 if (reexportingLibraries.containsKey(entity)) { | |
142 library = reexportingLibraries[entity]; | |
143 } | |
144 if (library.isPlatformLibrary) { | |
145 if (library.canonicalUri != Compiler.DART_CORE) { | |
146 platformImports.add(library); | |
147 } | |
148 if (library.isInternalLibrary) { | |
149 throw new SpannableAssertionFailure(entity, | |
150 "Internal library $library should never have been imported from " | |
151 "the code compiled by dart2dart."); | |
152 } | |
153 return entity.name; | |
154 } | |
155 } | |
156 String name = _renamedCache.putIfAbsent(entity, | |
157 () => _generateUniqueTopLevelName(entity.name)); | |
158 // Look up in [_renamedCache] for a name for [entity] . | |
159 // If it was not renamed before, generate a new name. | |
160 return name; | |
161 } | |
162 | |
163 void _computeMinifiedRenames(PlaceholderCollector placeholderCollector) { | |
164 _generator = new MinifyingGenerator(); | |
165 | |
166 // Build a list sorted by usage of local nodes that will be renamed to | |
167 // the same identifier. So the top-used local variables in all functions | |
168 // will be renamed first and will all share the same new identifier. | |
169 int maxLength = placeholderCollector.functionScopes.values.fold(0, | |
170 (a, b) => max(a, b.localPlaceholders.length)); | |
171 | |
172 List<Set<Node>> allLocals = new List<Set<Node>> | |
173 .generate(maxLength, (_) => new Set<Node>()); | |
174 | |
175 for (FunctionScope functionScope | |
176 in placeholderCollector.functionScopes.values) { | |
177 // Add current sorted local identifiers to the whole sorted list | |
178 // of all local identifiers for all functions. | |
179 List<LocalPlaceholder> currentSortedPlaceholders = | |
180 sorted(functionScope.localPlaceholders, | |
181 compareBy((LocalPlaceholder ph) => -ph.nodes.length)); | |
182 | |
183 List<Set<Node>> currentSortedNodes = currentSortedPlaceholders | |
184 .map((LocalPlaceholder ph) => ph.nodes).toList(); | |
185 | |
186 for (int i = 0; i < currentSortedNodes.length; i++) { | |
187 allLocals[i].addAll(currentSortedNodes[i]); | |
188 } | |
189 } | |
190 | |
191 // Rename elements, members and locals together based on their usage | |
192 // count, otherwise when we rename elements first there will be no good | |
193 // identifiers left for members even if they are used often. | |
194 List<Renamable> renamables = new List<Renamable>(); | |
195 placeholderCollector.elementNodes.forEach( | |
196 (Element element, Set<Node> nodes) { | |
197 renamables.add(new GlobalRenamable(element, nodes)); | |
198 }); | |
199 placeholderCollector.memberPlaceholders.forEach( | |
200 (String memberName, Set<Identifier> identifiers) { | |
201 renamables.add(new MemberRenamable(memberName, identifiers)); | |
202 }); | |
203 for (Set<Node> localIdentifiers in allLocals) { | |
204 renamables.add(new LocalRenamable(localIdentifiers)); | |
205 } | |
206 renamables.sort(); | |
207 for (Renamable renamable in renamables) { | |
208 String newName = renamable.createNewName(this); | |
209 _renameNodes(renamable.nodes, (_) => newName); | |
210 } | |
211 } | |
212 | |
213 void _computeNonMinifiedRenames(PlaceholderCollector placeholderCollector) { | |
214 _generator = new ConservativeGenerator(); | |
215 // Rename elements. | |
216 placeholderCollector.elementNodes.forEach( | |
217 (Element element, Set<Node> nodes) { | |
218 _renameNodes(nodes, (_) => _renameGlobal(element)); | |
219 }); | |
220 | |
221 // Rename locals. | |
222 placeholderCollector.functionScopes.forEach( | |
223 (functionElement, functionScope) { | |
224 | |
225 Set<String> memberIdentifiers = new Set<String>(); | |
226 Set<LocalPlaceholder> placeholders = functionScope.localPlaceholders; | |
227 if (functionElement.enclosingClass != null) { | |
228 functionElement.enclosingClass.forEachMember( | |
229 (enclosingClass, member) { | |
230 memberIdentifiers.add(member.name); | |
231 }); | |
232 } | |
233 Set<String> usedLocalIdentifiers = new Set<String>(); | |
234 for (LocalPlaceholder placeholder in placeholders) { | |
235 String nextId = _generator.generate(placeholder.identifier, (name) { | |
236 return functionScope.parameterIdentifiers.contains(name) | |
237 || _forbiddenIdentifiers.contains(name) | |
238 || usedLocalIdentifiers.contains(name) | |
239 || memberIdentifiers.contains(name); | |
240 }); | |
241 usedLocalIdentifiers.add(nextId); | |
242 _renameNodes(placeholder.nodes, (_) => nextId); | |
243 } | |
244 }); | |
245 | |
246 // Do not rename members to top-levels, that allows to avoid renaming | |
247 // members to constructors. | |
248 placeholderCollector.memberPlaceholders.forEach((identifier, nodes) { | |
249 String newIdentifier = _generateMemberName(identifier); | |
250 _renameNodes(nodes, (_) => newIdentifier); | |
251 }); | |
252 } | |
253 | |
254 /// Finds renamings for all the placeholders in [placeholderCollector] and | |
255 /// stores them in [renames]. | |
256 /// Also adds to [platformImports] all the platform-libraries that are used. | |
257 void computeRenames(PlaceholderCollector placeholderCollector) { | |
258 _allNamedParameterIdentifiers = new Set<String>(); | |
259 for (FunctionScope functionScope in | |
260 placeholderCollector.functionScopes.values) { | |
261 _allNamedParameterIdentifiers.addAll(functionScope.parameterIdentifiers); | |
262 } | |
263 | |
264 _forbiddenIdentifiers = new Set<String>.from(fixedMemberNames); | |
265 _forbiddenIdentifiers.addAll(Keyword.keywords.keys); | |
266 _forbiddenIdentifiers.add('main'); | |
267 | |
268 if (enableMinification) { | |
269 _computeMinifiedRenames(placeholderCollector); | |
270 } else { | |
271 _computeNonMinifiedRenames(placeholderCollector); | |
272 } | |
273 | |
274 // Rename constructors. | |
275 for (ConstructorPlaceholder placeholder in | |
276 placeholderCollector.constructorPlaceholders) { | |
277 renames[placeholder.node] = | |
278 _renameConstructor(placeholder); | |
279 }; | |
280 | |
281 // Rename private identifiers uniquely for each library. | |
282 placeholderCollector.privateNodes.forEach( | |
283 (LibraryElement library, Set<Identifier> identifiers) { | |
284 for (Identifier identifier in identifiers) { | |
285 renames[identifier] = _getPrivateName(library, identifier.source); | |
286 } | |
287 }); | |
288 | |
289 // Rename unresolved nodes, to make sure they still do not resolve. | |
290 for (Node node in placeholderCollector.unresolvedNodes) { | |
291 renames[node] = _generateUniqueTopLevelName('Unresolved'); | |
292 } | |
293 | |
294 // Erase prefixes that are now not needed. | |
295 for (Node node in placeholderCollector.prefixNodesToErase) { | |
296 renames[node] = ''; | |
297 } | |
298 | |
299 if (cutDeclarationTypes) { | |
300 for (DeclarationTypePlaceholder placeholder in | |
301 placeholderCollector.declarationTypePlaceholders) { | |
302 renames[placeholder.typeNode] = placeholder.requiresVar ? 'var' : ''; | |
303 } | |
304 } | |
305 } | |
306 } | |
307 | |
308 /** | |
309 * Generates mini ID based on index. | |
310 * In other words, it converts index to visual representation | |
311 * as if digits are given characters. | |
312 */ | |
313 String generateMiniId(int index) { | |
314 const String firstCharAlphabet = | |
315 r'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; | |
316 const String otherCharsAlphabet = | |
317 r'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$'; | |
318 // It's like converting index in decimal to [chars] radix. | |
319 if (index < firstCharAlphabet.length) return firstCharAlphabet[index]; | |
320 StringBuffer resultBuilder = new StringBuffer(); | |
321 resultBuilder.writeCharCode( | |
322 firstCharAlphabet.codeUnitAt(index % firstCharAlphabet.length)); | |
323 index ~/= firstCharAlphabet.length; | |
324 int length = otherCharsAlphabet.length; | |
325 while (index >= length) { | |
326 resultBuilder.writeCharCode(otherCharsAlphabet.codeUnitAt(index % length)); | |
327 index ~/= length; | |
328 } | |
329 resultBuilder.write(otherCharsAlphabet[index]); | |
330 return resultBuilder.toString(); | |
331 } | |
332 | |
333 abstract class Generator { | |
334 String generate(String originalName, bool isForbidden(String name)); | |
335 } | |
336 | |
337 /// Always tries to return original identifier name unless it is forbidden. | |
338 class ConservativeGenerator implements Generator { | |
339 String generate(String originalName, bool isForbidden(String name)) { | |
340 String result = originalName; | |
341 int index = 0; | |
342 while (isForbidden(result) ){ //|| result == originalName) { | |
343 result = '${originalName}_${generateMiniId(index++)}'; | |
344 } | |
345 return result; | |
346 } | |
347 } | |
348 | |
349 /// Always tries to generate the most compact identifier. | |
350 class MinifyingGenerator implements Generator { | |
351 int index = 0; | |
352 | |
353 MinifyingGenerator(); | |
354 | |
355 String generate(String originalName, bool isForbidden(String name)) { | |
356 String result; | |
357 do { | |
358 result = generateMiniId(index++); | |
359 } while (isForbidden(result)); | |
360 return result; | |
361 } | |
362 } | |
OLD | NEW |