| 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 |