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

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

Issue 891673003: dart2js: Refactoring, documentation, and a few bugfixes in Namer class. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 months 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
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 *
10 * Names are generated through three stages:
11 *
12 * 1. Original names and proposed names
13 * 2. Disambiguated names (also known as "mangled names")
14 * 3. Annotated names
15 *
16 * Original names are names taken directly from the input.
17 *
18 * Proposed names are either original names or synthesized names for input
19 * elements that do not have original names.
20 *
21 * Disambiguated names are derived from the above, but are mangled to ensure
22 * uniqueness within some namespace (e.g. as fields on the same JS object).
23 * In [MinifyNamer], disambiguated names are also minified.
24 *
25 * Annotated names are names generated from a disambiguated name. Annnotated
26 * names must be computable at runtime by prefixing/suffixing constant strings
27 * onto the disambiguated name.
28 *
29 * For example, some entity called `x` might be associated with these names:
30 *
31 * Original name: `x`
32 *
33 * Disambiguated name: `x1` (if something else was called `x`)
34 *
35 * Annotated names: `x1` (field name)
36 * `get$x1` (getter name)
37 * `set$x1` (setter name)
38 * `x1$2` (if `x` is a method with 2 parameters)
39 *
40 * The [Namer] can choose the disambiguated names, and to some degree the
41 * prefix/suffix constants used to construct annotated names. It cannot choose
42 * annotated names with total freedom, for example, it cannot choose that the
43 * getter for `x1` should be called `getX` -- the annotated names are always
44 * built by concatenation.
45 *
46 * Disambiguated names must be chosen such that none of the annotated names can
47 * clash with each other. This may happen even if the disambiguated names are
48 * distinct, for example, suppose a field `x` and `get$x` exists in the input:
49 *
50 * Original names: `x` and `get$x`
51 *
52 * Disambiguated names: `x` and `get$x` (the two names a different)
53 *
54 * Annotated names: `x` (field for `x`)
55 * `get$x` (getter for `x`)
56 * `get$x` (field for `get$x`)
57 * `get$get$x` (getter for `get$x`)
58 *
59 * The getter for `x` clashes with the field name for `get$x`, so the
60 * disambiguated names are invalid.
61 *
62 * Additionally, disambiguated names must be chosen such that all annotated
63 * names are valid JavaScript identifiers and do not coincide with a native
64 * JavaScript property such as `__proto__`.
65 *
66 * The following annotated names are generated for instance members, where
67 * <NAME> denotes the disambiguated name.
68 *
69 * 0. The disambiguated name can itself be seen as a annotated name.
70 *
71 * 1. Multiple annotated names exist per method name, encoding arity and named
72 * parameters with the pattern:
73 *
74 * <NAME>$<N>$namedParam1...$namedParam<M>
75 *
76 * where <N> is the number of parameters (required and optional) and <M> is
77 * the number of named parameters, and namedParam<n> are the names of the
78 * named parameters in alphabetical order.
79 *
80 * Note that this convention is not encapsulated in the [Namer], and is
81 * hardcoded into other components, such as [Element] and [Selector].
82 *
83 * 2. The getter/setter for a field, or tear-off getter for a method:
84 *
85 * get$<NAME>
86 * set$<NAME>
87 *
88 * (The [getterPrefix] and [setterPrefix] are different in [MinifyNamer]).
89 *
90 * 3. The `is` and operator uses the following names:
91 *
92 * $is<NAME>
93 * $as<NAME>
94 *
95 * For local variables, the [Namer] only provides *proposed names*. These names
96 * must be disambiguated elsewhere.
9 */ 97 */
10 class Namer implements ClosureNamer { 98 class Namer implements ClosureNamer {
11 99
12 static const javaScriptKeywords = const <String>[ 100 static const List<String> javaScriptKeywords = const <String>[
13 // These are current keywords. 101 // These are current keywords.
14 "break", "delete", "function", "return", "typeof", "case", "do", "if", 102 "break", "delete", "function", "return", "typeof", "case", "do", "if",
15 "switch", "var", "catch", "else", "in", "this", "void", "continue", 103 "switch", "var", "catch", "else", "in", "this", "void", "continue",
16 "false", "instanceof", "throw", "while", "debugger", "finally", "new", 104 "false", "instanceof", "throw", "while", "debugger", "finally", "new",
17 "true", "with", "default", "for", "null", "try", 105 "true", "with", "default", "for", "null", "try",
18 106
19 // These are future keywords. 107 // These are future keywords.
20 "abstract", "double", "goto", "native", "static", "boolean", "enum", 108 "abstract", "double", "goto", "native", "static", "boolean", "enum",
21 "implements", "package", "super", "byte", "export", "import", "private", 109 "implements", "package", "super", "byte", "export", "import", "private",
22 "synchronized", "char", "extends", "int", "protected", "throws", 110 "synchronized", "char", "extends", "int", "protected", "throws",
23 "class", "final", "interface", "public", "transient", "const", "float", 111 "class", "final", "interface", "public", "transient", "const", "float",
24 "long", "short", "volatile" 112 "long", "short", "volatile"
25 ]; 113 ];
26 114
27 static const reservedPropertySymbols = 115 static const List<String> reservedPropertySymbols =
28 const <String>["__proto__", "prototype", "constructor", "call"]; 116 const <String>["__proto__", "prototype", "constructor", "call"];
29 117
30 // Symbols that we might be using in our JS snippets. 118 // Symbols that we might be using in our JS snippets.
31 static const reservedGlobalSymbols = const <String>[ 119 static const List<String> reservedGlobalSymbols = const <String>[
32 // Section references are from Ecma-262 120 // Section references are from Ecma-262
33 // (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pd f) 121 // (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pd f)
34 122
35 // 15.1.1 Value Properties of the Global Object 123 // 15.1.1 Value Properties of the Global Object
36 "NaN", "Infinity", "undefined", 124 "NaN", "Infinity", "undefined",
37 125
38 // 15.1.2 Function Properties of the Global Object 126 // 15.1.2 Function Properties of the Global Object
39 "eval", "parseInt", "parseFloat", "isNaN", "isFinite", 127 "eval", "parseInt", "parseFloat", "isNaN", "isFinite",
40 128
41 // 15.1.3 URI Handling Function Properties 129 // 15.1.3 URI Handling Function Properties
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 "Table", "TableCell", "TableRow", "TableSelection", "Text", "TextArea", 229 "Table", "TableCell", "TableRow", "TableSelection", "Text", "TextArea",
142 "UIEvent", "Window", "XMLHttpRequest", "XMLSerializer", 230 "UIEvent", "Window", "XMLHttpRequest", "XMLSerializer",
143 "XPathException", "XPathResult", "XSLTProcessor", 231 "XPathException", "XPathResult", "XSLTProcessor",
144 232
145 // These keywords trigger the loading of the java-plugin. For the 233 // These keywords trigger the loading of the java-plugin. For the
146 // next-generation plugin, this results in starting a new Java process. 234 // next-generation plugin, this results in starting a new Java process.
147 "java", "Packages", "netscape", "sun", "JavaObject", "JavaClass", 235 "java", "Packages", "netscape", "sun", "JavaObject", "JavaClass",
148 "JavaArray", "JavaMember", 236 "JavaArray", "JavaMember",
149 ]; 237 ];
150 238
151 static const reservedGlobalObjectNames = const <String>[ 239 static const List<String> reservedGlobalObjectNames = const <String>[
152 "A", 240 "A",
153 "B", 241 "B",
154 "C", // Global object for *C*onstants. 242 "C", // Global object for *C*onstants.
155 "D", 243 "D",
156 "E", 244 "E",
157 "F", 245 "F",
158 "G", 246 "G",
159 "H", // Global object for internal (*H*elper) libraries. 247 "H", // Global object for internal (*H*elper) libraries.
160 // I is used for used for the Isolate function. 248 // I is used for used for the Isolate function.
161 "J", // Global object for the interceptor library. 249 "J", // Global object for the interceptor library.
162 "K", 250 "K",
163 "L", 251 "L",
164 "M", 252 "M",
165 "N", 253 "N",
166 "O", 254 "O",
167 "P", // Global object for other *P*latform libraries. 255 "P", // Global object for other *P*latform libraries.
168 "Q", 256 "Q",
169 "R", 257 "R",
170 "S", 258 "S",
171 "T", 259 "T",
172 "U", 260 "U",
173 "V", 261 "V",
174 "W", // Global object for *W*eb libraries (dart:html). 262 "W", // Global object for *W*eb libraries (dart:html).
175 "X", 263 "X",
176 "Y", 264 "Y",
177 "Z", 265 "Z",
178 ]; 266 ];
179 267
180 static const reservedGlobalHelperFunctions = const <String>[ 268 static const List<String> reservedGlobalHelperFunctions = const <String>[
181 "init", 269 "init",
182 "Isolate", 270 "Isolate",
183 ]; 271 ];
184 272
185 static final userGlobalObjects = new List.from(reservedGlobalObjectNames) 273 static final List<String> userGlobalObjects =
274 new List.from(reservedGlobalObjectNames)
186 ..remove('C') 275 ..remove('C')
187 ..remove('H') 276 ..remove('H')
188 ..remove('J') 277 ..remove('J')
189 ..remove('P') 278 ..remove('P')
190 ..remove('W'); 279 ..remove('W');
191 280
192 Set<String> _jsReserved = null; 281 Set<String> _jsReserved = null;
193 /// Names that cannot be used by members, top level and static 282 /// Names that cannot be used by members, top level and static
194 /// methods. 283 /// methods.
195 Set<String> get jsReserved { 284 Set<String> get jsReserved {
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
245 * by [getName]. 334 * by [getName].
246 * 335 *
247 * Invariant: Keys must be declaration elements. 336 * Invariant: Keys must be declaration elements.
248 */ 337 */
249 final Compiler compiler; 338 final Compiler compiler;
250 final Map<Element, String> globals; 339 final Map<Element, String> globals;
251 final Map<String, LibraryElement> shortPrivateNameOwners; 340 final Map<String, LibraryElement> shortPrivateNameOwners;
252 341
253 final Set<String> usedGlobalNames; 342 final Set<String> usedGlobalNames;
254 final Set<String> usedInstanceNames; 343 final Set<String> usedInstanceNames;
255 final Map<String, String> globalNameMap; 344 final Map<String, String> internGlobals;
256 final Map<String, String> suggestedGlobalNames; 345 final Map<String, String> suggestedGlobalNames;
257 final Map<String, String> instanceNameMap; 346 final Map<LibraryElement, Map<String, String>> instanceMembers;
258 final Map<String, String> suggestedInstanceNames; 347 final Map<String, String> suggestedInstanceNames;
348 final Map<Element, String> directAccessMap = <Element, String>{};
259 349
260 final Map<String, String> operatorNameMap; 350 final Map<String, String> operatorNameMap;
261 final Map<String, int> popularNameCounters; 351 final Map<String, int> popularNameCounters;
262 352
263 final Map<ConstantValue, String> constantNames; 353 final Map<ConstantValue, String> constantNames;
264 final Map<ConstantValue, String> constantLongNames; 354 final Map<ConstantValue, String> constantLongNames;
265 ConstantCanonicalHasher constantHasher; 355 ConstantCanonicalHasher constantHasher;
266 356
267 // All alphanumeric characters. 357 // All alphanumeric characters.
268 static const String _alphaNumeric = 358 static const String _alphaNumeric =
269 'abcdefghijklmnopqrstuvwxyzABZDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; 359 'abcdefghijklmnopqrstuvwxyzABZDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
270 360
271 Namer(Compiler compiler) 361 Namer(Compiler compiler)
272 : compiler = compiler, 362 : compiler = compiler,
273 globals = new Map<Element, String>(), 363 globals = new Map<Element, String>(),
274 shortPrivateNameOwners = new Map<String, LibraryElement>(), 364 shortPrivateNameOwners = new Map<String, LibraryElement>(),
275 usedGlobalNames = new Set<String>(), 365 usedGlobalNames = new Set<String>(),
276 usedInstanceNames = new Set<String>(), 366 usedInstanceNames = new Set<String>(),
277 instanceNameMap = new Map<String, String>(), 367 instanceMembers = new Map<LibraryElement, Map<String, String>>(),
278 operatorNameMap = new Map<String, String>(), 368 operatorNameMap = new Map<String, String>(),
279 globalNameMap = new Map<String, String>(), 369 internGlobals = new Map<String, String>(),
280 suggestedGlobalNames = new Map<String, String>(), 370 suggestedGlobalNames = new Map<String, String>(),
281 suggestedInstanceNames = new Map<String, String>(), 371 suggestedInstanceNames = new Map<String, String>(),
282 popularNameCounters = new Map<String, int>(), 372 popularNameCounters = new Map<String, int>(),
283 constantNames = new Map<ConstantValue, String>(), 373 constantNames = new Map<ConstantValue, String>(),
284 constantLongNames = new Map<ConstantValue, String>(), 374 constantLongNames = new Map<ConstantValue, String>(),
285 constantHasher = new ConstantCanonicalHasher(compiler), 375 constantHasher = new ConstantCanonicalHasher(compiler),
286 functionTypeNamer = new FunctionTypeNamer(compiler); 376 functionTypeNamer = new FunctionTypeNamer(compiler);
287 377
288 JavaScriptBackend get backend => compiler.backend; 378 JavaScriptBackend get backend => compiler.backend;
289 379
(...skipping 16 matching lines...) Expand all
306 case 'REFLECTABLE': return reflectableField; 396 case 'REFLECTABLE': return reflectableField;
307 case 'CLASS_DESCRIPTOR_PROPERTY': return classDescriptorProperty; 397 case 'CLASS_DESCRIPTOR_PROPERTY': return classDescriptorProperty;
308 default: 398 default:
309 compiler.reportError( 399 compiler.reportError(
310 node, MessageKind.GENERIC, 400 node, MessageKind.GENERIC,
311 {'text': 'Error: Namer has no name for "$name".'}); 401 {'text': 'Error: Namer has no name for "$name".'});
312 return 'BROKEN'; 402 return 'BROKEN';
313 } 403 }
314 } 404 }
315 405
406 /// Disambiguated name for [constant].
407 ///
408 /// Unique within the global-member namespace.
316 String constantName(ConstantValue constant) { 409 String constantName(ConstantValue constant) {
317 // In the current implementation it doesn't make sense to give names to 410 // In the current implementation it doesn't make sense to give names to
318 // function constants since the function-implementation itself serves as 411 // function constants since the function-implementation itself serves as
319 // constant and can be accessed directly. 412 // constant and can be accessed directly.
320 assert(!constant.isFunction); 413 assert(!constant.isFunction);
321 String result = constantNames[constant]; 414 String result = constantNames[constant];
322 if (result == null) { 415 if (result == null) {
323 String longName = constantLongName(constant); 416 String longName = constantLongName(constant);
324 result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames, 417 result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames,
325 ensureSafe: true); 418 ensureSafe: true);
326 constantNames[constant] = result; 419 constantNames[constant] = result;
327 } 420 }
328 return result; 421 return result;
329 } 422 }
330 423
331 // The long name is unminified and may have collisions. 424 /// Proposed name for [constant].
332 String constantLongName(ConstantValue constant) { 425 String constantLongName(ConstantValue constant) {
333 String longName = constantLongNames[constant]; 426 String longName = constantLongNames[constant];
334 if (longName == null) { 427 if (longName == null) {
335 longName = new ConstantNamingVisitor(compiler, constantHasher) 428 longName = new ConstantNamingVisitor(compiler, constantHasher)
336 .getName(constant); 429 .getName(constant);
337 constantLongNames[constant] = longName; 430 constantLongNames[constant] = longName;
338 } 431 }
339 return longName; 432 return longName;
340 } 433 }
341 434
342 String breakLabelName(LabelDefinition label) { 435 String breakLabelName(LabelDefinition label) {
343 return '\$${label.labelName}\$${label.target.nestingLevel}'; 436 return '\$${label.labelName}\$${label.target.nestingLevel}';
344 } 437 }
345 438
346 String implicitBreakLabelName(JumpTarget target) { 439 String implicitBreakLabelName(JumpTarget target) {
347 return '\$${target.nestingLevel}'; 440 return '\$${target.nestingLevel}';
348 } 441 }
349 442
350 // We sometimes handle continue targets differently from break targets, 443 // We sometimes handle continue targets differently from break targets,
351 // so we have special continue-only labels. 444 // so we have special continue-only labels.
352 String continueLabelName(LabelDefinition label) { 445 String continueLabelName(LabelDefinition label) {
353 return 'c\$${label.labelName}\$${label.target.nestingLevel}'; 446 return 'c\$${label.labelName}\$${label.target.nestingLevel}';
354 } 447 }
355 448
356 String implicitContinueLabelName(JumpTarget target) { 449 String implicitContinueLabelName(JumpTarget target) {
357 return 'c\$${target.nestingLevel}'; 450 return 'c\$${target.nestingLevel}';
358 } 451 }
359 452
360 /** 453 /**
361 * If the [name] is not private returns [:name:]. Otherwise 454 * If the [originalName] is not private returns [originalName]. Otherwise
362 * mangles the [name] so that each library has a unique name. 455 * mangles the [originalName] so that each library has its own distinguished
456 * version of the name.
457 *
458 * Although the name is not guaranteed to be unique within any namespace,
459 * clashes are very unlikely in practice. Therefore, it can be used in cases
460 * where uniqueness is nice but not a strict requirement.
461 *
462 * The resulting name is a *proposed name* and is never minified.
363 */ 463 */
364 String privateName(LibraryElement library, String name) { 464 String privateName(LibraryElement library, String originalName) {
365 // Public names are easy. 465 // Public names are easy.
366 String nameString = name; 466 if (!isPrivateName(originalName)) return originalName;
367 if (!isPrivateName(name)) return nameString;
368 467
369 // The first library asking for a short private name wins. 468 // The first library asking for a short private name wins.
370 LibraryElement owner = 469 LibraryElement owner =
371 shortPrivateNameOwners.putIfAbsent(nameString, () => library); 470 shortPrivateNameOwners.putIfAbsent(originalName, () => library);
372 471
373 if (owner == library && !nameString.contains('\$')) { 472 if (owner == library && !originalName.contains('\$')) {
374 // Since the name doesn't contain $ it doesn't clash with any 473 // Since the name doesn't contain $ it doesn't clash with any
375 // of the private names that have the library name as the prefix. 474 // of the private names that have the library name as the prefix.
376 return nameString; 475 return originalName;
377 } else { 476 } else {
378 // Make sure to return a private name that starts with _ so it 477 // Make sure to return a private name that starts with _ so it
379 // cannot clash with any public names. 478 // cannot clash with any public names.
380 String libraryName = getNameOfLibrary(library); 479 String libraryName = disambiguateGlobal(library);
381 return '_$libraryName\$$nameString'; 480 return '_$libraryName\$${originalName}';
382 } 481 }
383 } 482 }
384 483
385 String instanceMethodName(FunctionElement element) { 484 /// Annotated name for [method] encoding arity and named parameters.
386 // TODO(ahe): Could this be: return invocationName(new 485 String instanceMethodName(FunctionElement method) {
387 // Selector.fromElement(element))? 486 if (method.isGenerativeConstructorBody) {
388 String elementName = element.name; 487 return disambiguateDirectAccess(method,
389 String name = operatorNameToIdentifier(elementName); 488 () => Elements.reconstructConstructorNameSourceString(method));
390 if (name != elementName) return getMappedOperatorName(name);
391
392 LibraryElement library = element.library;
393 if (element.isGenerativeConstructorBody) {
394 name = Elements.reconstructConstructorNameSourceString(element);
395 } 489 }
396 FunctionSignature signature = element.functionSignature; 490 return invocationName(new Selector.fromElement(method));
397 // We don't mangle the closure invoking function name because it
398 // is generated by string concatenation in applyFunction from
399 // js_helper.dart. To keep code size down, we potentially shorten
400 // the prefix though.
401 String methodName;
402 if (name == closureInvocationSelectorName) {
403 methodName = '$callPrefix\$${signature.parameterCount}';
404 } else {
405 methodName = '${privateName(library, name)}\$${signature.parameterCount}';
406 }
407 if (signature.optionalParametersAreNamed &&
408 !signature.optionalParameters.isEmpty) {
409 StringBuffer buffer = new StringBuffer();
410 signature.orderedOptionalParameters.forEach((Element element) {
411 buffer.write('\$${safeName(element.name)}');
412 });
413 methodName = '$methodName$buffer';
414 }
415 if (name == closureInvocationSelectorName) return methodName;
416 return getMappedInstanceName(methodName);
417 } 491 }
418 492
419 String publicInstanceMethodNameByArity(String name, int arity) { 493 /// Annotated name for a public method with the given [originalName]
420 String newName = operatorNameToIdentifier(name); 494 /// and [arity] and no named parameters.
421 if (newName != name) return getMappedOperatorName(newName); 495 String publicInstanceMethodNameByArity(String originalName, int arity) {
422 assert(!isPrivateName(name)); 496 String opName = operatorNameToIdentifier(originalName);
423 // We don't mangle the closure invoking function name because it 497 if (opName != originalName) return disambiguateOperator(opName);
424 // is generated by string concatenation in applyFunction from 498 assert(!isPrivateName(originalName));
425 // js_helper.dart. To keep code size down, we potentially shorten 499 String disambiguatedName = disambiguateMember(null, originalName);
426 // the prefix though. 500 Selector selector = new Selector.call(originalName, null, arity);
427 if (name == closureInvocationSelectorName) return '$callPrefix\$$arity'; 501 return deriveMethodName(disambiguatedName, selector);
asgerf 2015/01/30 15:20:29 The closureInvocationSelectorName logic has been i
428
429 return getMappedInstanceName('$name\$$arity');
430 } 502 }
431 503
504 /// Returns the annotated name for a method with the given name,
505 /// encoding arity and named parameters with the pattern:
506 ///
507 /// <NAME>$<N>$namedParam1...$namedParam<M>
508 ///
509 String deriveMethodName(String disambiguatedName, Selector selector) {
510 assert(selector.isCall);
511 StringBuffer buffer = new StringBuffer();
512 for (String argumentName in selector.getOrderedNamedArguments()) {
513 buffer.write('\$${safeName(argumentName)}');
514 }
515 return '$disambiguatedName\$${selector.argumentCount}$buffer';
516 }
517
518 /// Annotated name for the member being invoked by [selector].
432 String invocationName(Selector selector) { 519 String invocationName(Selector selector) {
433 if (selector.isGetter) { 520 LibraryElement library = selector.library;
434 String proposedName = privateName(selector.library, selector.name); 521 switch (selector.kind) {
435 return '$getterPrefix${getMappedInstanceName(proposedName)}'; 522 case SelectorKind.GETTER:
436 } else if (selector.isSetter) { 523 String disambiguatedName = disambiguateMember(library, selector.name);
437 String proposedName = privateName(selector.library, selector.name); 524 return deriveGetterName(disambiguatedName);
438 return '$setterPrefix${getMappedInstanceName(proposedName)}'; 525
439 } else { 526 case SelectorKind.SETTER:
440 String name = selector.name; 527 String disambiguatedName = disambiguateMember(library, selector.name);
441 if (selector.kind == SelectorKind.OPERATOR 528 return deriveSetterName(disambiguatedName);
442 || selector.kind == SelectorKind.INDEX) { 529
443 name = operatorNameToIdentifier(name); 530 case SelectorKind.OPERATOR:
444 assert(name != selector.name); 531 case SelectorKind.INDEX:
445 return getMappedOperatorName(name); 532 String operatorIdentifier = operatorNameToIdentifier(selector.name);
446 } 533 String disambiguatedName = disambiguateOperator(operatorIdentifier);
447 assert(name == operatorNameToIdentifier(name)); 534 return disambiguatedName; // Operators are not annotated.
448 StringBuffer buffer = new StringBuffer(); 535
449 for (String argumentName in selector.getOrderedNamedArguments()) { 536 case SelectorKind.CALL:
450 buffer.write('\$${safeName(argumentName)}'); 537 String disambiguatedName = disambiguateMember(library, selector.name);
451 } 538 return deriveMethodName(disambiguatedName, selector);
452 String suffix = '\$${selector.argumentCount}$buffer'; 539
453 // We don't mangle the closure invoking function name because it 540 default: throw 'Unexpected selector kind: ${selector.kind}';
454 // is generated by string concatenation in applyFunction from
455 // js_helper.dart. We potentially shorten the prefix though.
456 if (selector.isClosureCall) {
457 return "$callPrefix$suffix";
458 } else {
459 String proposedName = privateName(selector.library, name);
460 return getMappedInstanceName('$proposedName$suffix');
461 }
462 } 541 }
463 } 542 }
464 543
465 /** 544 /**
466 * Returns the internal name used for an invocation mirror of this selector. 545 * Returns the internal name used for an invocation mirror of this selector.
467 */ 546 */
468 String invocationMirrorInternalName(Selector selector) 547 String invocationMirrorInternalName(Selector selector)
469 => invocationName(selector); 548 => invocationName(selector);
470 549
471 /** 550 /**
472 * Returns name of accessor (root to getter and setter) for a static or 551 * Returns the disambiguated name for the given field, used for constructing
473 * instance field. 552 * the getter and setter names.
474 */ 553 */
475 String fieldAccessorName(Element element) { 554 String fieldAccessorName(Element element) {
476 return element.isInstanceMember 555 return element.isInstanceMember
477 ? instanceFieldAccessorName(element) 556 ? disambiguateMember(element.library, element.name)
478 : getNameOfField(element); 557 : disambiguateGlobal(element);
479 } 558 }
480 559
481 /** 560 /**
482 * Returns name of the JavaScript property used to store a static or instance 561 * Returns name of the JavaScript property used to store a static or instance
483 * field. 562 * field.
484 */ 563 */
485 String fieldPropertyName(Element element) { 564 String fieldPropertyName(Element element) {
486 return element.isInstanceMember 565 return element.isInstanceMember
487 ? instanceFieldPropertyName(element) 566 ? instanceFieldPropertyName(element)
488 : getNameOfField(element); 567 : disambiguateGlobal(element);
489 } 568 }
490 569
491 /** 570 /**
492 * Returns name of accessor (root to getter and setter) for an instance field. 571 * Returns name of the JavaScript property used to store the given type
572 * variable.
493 */ 573 */
494 String instanceFieldAccessorName(Element element) {
495 String proposedName = privateName(element.library, element.name);
496 return getMappedInstanceName(proposedName);
497 }
498
499 String readTypeVariableName(TypeVariableElement element) { 574 String readTypeVariableName(TypeVariableElement element) {
500 return '\$tv_${instanceFieldAccessorName(element)}'; 575 return disambiguateDirectAccess(element, () => element.name);
501 } 576 }
502 577
503 /** 578 /**
504 * Returns name of the JavaScript property used to store an instance field. 579 * Returns a JavaScript property name used to store [element] on one
580 * of the global objects.
581 *
582 * Should be used together with [globalObjectFor], which denotes the object
583 * on which the returned property name should be used.
584 */
585 String globalPropertyName(Element element) {
586 return disambiguateGlobal(element);
587 }
588
589 /**
590 * Returns the JavaScript property name used to store an instance field.
505 */ 591 */
506 String instanceFieldPropertyName(Element element) { 592 String instanceFieldPropertyName(Element element) {
507 if (element.hasFixedBackendName) { 593 if (element.hasFixedBackendName) {
508 return element.fixedBackendName; 594 return element.fixedBackendName;
509 } 595 }
510 // If a class is used anywhere as a mixin, we must make the name unique so 596
511 // that it does not accidentally shadow. Also, the mixin name must be 597 // If the name of the field might clash with another field,
512 // constant over all mixins. 598 // use a mangled field name to avoid potential clashes.
513 ClassWorld classWorld = compiler.world; 599 ClassWorld classWorld = compiler.world;
514 if (classWorld.isUsedAsMixin(element.enclosingClass) || 600 if (classWorld.isUsedAsMixin(element.enclosingClass) ||
515 shadowingAnotherField(element)) { 601 shadowingAnotherField(element)) {
516 // Construct a new name for the element based on the library and class it 602 return disambiguateDirectAccess(element,
517 // is in. The name here is not important, we just need to make sure it is 603 () => '${element.enclosingClass.name}_${element.name}');
518 // unique. If we are minifying, we actually construct the name from the 604 }
519 // minified version of the class name, but the result is minified once 605
520 // again, so that is not visible in the end result. 606 // No inheritance-related name clashes exist, so the accessor and property
521 String libraryName = getNameOfLibrary(element.library); 607 // name can be shared. This generates nicer field names since otherwise
522 String className = getNameOfClass(element.enclosingClass); 608 // one of them would have to be mangled.
523 String instanceName = privateName(element.library, element.name); 609 return disambiguateMember(element.library, element.name);
524 return getMappedInstanceName('$libraryName\$$className\$$instanceName'); 610 }
525 }
526
527 String proposedName = privateName(element.library, element.name);
528 return getMappedInstanceName(proposedName);
529 }
530
531 611
532 bool shadowingAnotherField(Element element) { 612 bool shadowingAnotherField(Element element) {
533 return element.enclosingClass.hasFieldShadowedBy(element); 613 return element.enclosingClass.hasFieldShadowedBy(element);
534 } 614 }
535 615
536 String setterName(Element element) { 616 /// Annotated name for the setter of [element].
617 String setterForElement(Element element) {
537 // We dynamically create setters from the field-name. The setter name must 618 // We dynamically create setters from the field-name. The setter name must
538 // therefore be derived from the instance field-name. 619 // therefore be derived from the instance field-name.
539 LibraryElement library = element.library; 620 String name = disambiguateMember(element.library, element.name);
540 String name = getMappedInstanceName(privateName(library, element.name)); 621 return deriveSetterName(name);
541 return '$setterPrefix$name'; 622 }
542 } 623
543 624 /// Annotated name for the setter of any member with [disambiguatedName].
544 String setterNameFromAccessorName(String name) { 625 String deriveSetterName(String disambiguatedName) {
545 // We dynamically create setters from the field-name. The setter name must 626 // We dynamically create setters from the field-name. The setter name must
546 // therefore be derived from the instance field-name. 627 // therefore be derived from the instance field-name.
547 return '$setterPrefix$name'; 628 return '$setterPrefix$disambiguatedName';
548 } 629 }
549 630
550 String getterNameFromAccessorName(String name) { 631 /// Annotated name for the setter of any member with [disambiguatedName].
632 String deriveGetterName(String disambiguatedName) {
551 // We dynamically create getters from the field-name. The getter name must 633 // We dynamically create getters from the field-name. The getter name must
552 // therefore be derived from the instance field-name. 634 // therefore be derived from the instance field-name.
553 return '$getterPrefix$name'; 635 return '$getterPrefix$disambiguatedName';
554 } 636 }
555 637
556 String getterName(Element element) { 638 /// Annotated name for the getter of [element].
639 String getterForElement(Element element) {
557 // We dynamically create getters from the field-name. The getter name must 640 // We dynamically create getters from the field-name. The getter name must
558 // therefore be derived from the instance field-name. 641 // therefore be derived from the instance field-name.
559 LibraryElement library = element.library; 642 String name = disambiguateMember(element.library, element.name);
560 String name = getMappedInstanceName(privateName(library, element.name)); 643 return deriveGetterName(name);
561 return '$getterPrefix$name'; 644 }
562 } 645
563 646 /// Property name for the getter of an instance member with [originalName]
564 String getMappedGlobalName(String proposedName, {bool ensureSafe: true}) { 647 /// in [library].
565 var newName = globalNameMap[proposedName]; 648 ///
566 if (newName == null) { 649 /// [library] may be `null` if [originalName] is known to be public.
650 String getterForMember(LibraryElement library, String originalName) {
651 String disambiguatedName = disambiguateMember(library, originalName);
652 return deriveGetterName(disambiguatedName);
653 }
654
655 /// Disambiguated name for a compiler-owned global variable.
656 ///
657 /// The resulting name is unique within the global-member namespace.
658 String disambiguateInternGlobal(String name, {bool ensureSafe: true}) {
659 String newName = internGlobals[name];
660 if (newName == null) {
661 newName = getFreshName(name, usedGlobalNames,
662 suggestedGlobalNames, ensureSafe: ensureSafe);
663 internGlobals[name] = newName;
664 }
665 return newName;
666 }
667
668 /// Returns the property name to use for a compiler-owner global variable,
669 /// i.e. one that does not correspond to any element but is used as a utility
670 /// global by code generation.
671 ///
672 /// [name] functions as both the proposed name for the global, and as a key
673 /// identifying the global. The [name] should not contain `$` symbols, since
674 /// the [Namer] uses those names internally.
675 ///
676 /// This provides an easy mechanism for avoiding a name-clash with user-space
677 /// globals, although the callers of must still take care not to accidentally
678 /// pass in the same [name] for two different intern globals.
679 String internGlobal(String name, {bool ensureSafe: true}) {
680 return disambiguateInternGlobal(name, ensureSafe: ensureSafe);
681 }
682
683 /// Returns the disambiguated name for a top-level or static element.
684 ///
685 /// The resulting name is unique within the global-member namespace.
686 String disambiguateGlobal(Element element) {
687 element = element.declaration;
688 String newName = globals[element];
689 if (newName == null) {
690 String proposedName = _proposeNameForGlobal(element);
567 newName = getFreshName(proposedName, usedGlobalNames, 691 newName = getFreshName(proposedName, usedGlobalNames,
568 suggestedGlobalNames, ensureSafe: ensureSafe); 692 suggestedGlobalNames, ensureSafe: true);
569 globalNameMap[proposedName] = newName; 693 globals[element] = newName;
570 } 694 }
571 return newName; 695 return newName;
572 } 696 }
573 697
574 String getMappedInstanceName(String proposedName) { 698 /// Returns the disambiguated name for an instance method or field
575 var newName = instanceNameMap[proposedName]; 699 /// with [originalName] in [library].
576 if (newName == null) { 700 ///
577 newName = getFreshName(proposedName, usedInstanceNames, 701 /// [library] may be `null` if [originalName] is known to be public.
578 suggestedInstanceNames, ensureSafe: true); 702 ///
579 instanceNameMap[proposedName] = newName; 703 /// This is the name used for deriving names of accessors (getters and
580 } 704 /// setters) and annotated method names (encoding arity and named parameters).
581 return newName; 705 ///
582 } 706 /// The resulting name, and its associated annotated names, are unique within
583 707 /// the instance-member namespace.
584 String getMappedOperatorName(String proposedName) { 708 String disambiguateMember(LibraryElement library, String originalName) {
585 var newName = operatorNameMap[proposedName]; 709 if (originalName == closureInvocationSelectorName) {
586 if (newName == null) { 710 // We hardcode the disambiguated name of 'call'.
587 newName = getFreshName(proposedName, usedInstanceNames, 711 return callPrefix;
712 }
713 if (!isPrivateName(originalName)) {
714 library = null;
715 }
716 Map<String, String> nameMap =
717 instanceMembers.putIfAbsent(library, () => new Map<String,String>());
718 String newName = nameMap[originalName];
719 if (newName == null) {
720 String proposedName = privateName(library, originalName);
721 newName = getFreshName(proposedName,
722 usedInstanceNames, suggestedInstanceNames,
723 ensureSafe: true,
724 sanitizeForAnnotations: true);
725 nameMap[originalName] = newName;
726 }
727 return newName;
728 }
729
730 /// Disambiguated name unique to [element].
731 ///
732 /// This is used as the property name for fields, type variables,
733 /// constructor bodies, and super-accessors.
734 ///
735 /// The resulting name is unique within the instance-member namespace.
736 String disambiguateDirectAccess(Element element, String proposeName()) {
737 String newName = directAccessMap[element];
738 if (newName == null) {
739 String name = proposeName();
740 newName = getFreshName(name,
741 usedInstanceNames, suggestedInstanceNames,
742 ensureSafe: true,
743 sanitizeForAnnotations: true);
744 directAccessMap[element] = newName;
745 }
746 return newName;
747 }
748
749 /// Disambiguated name for the given operator.
750 ///
751 /// [operatorIdentifier] must be the operator's identifier, e.g.
752 /// `$add` and not `+`.
753 ///
754 /// The resulting name is unique within the instance-member namespace.
755 String disambiguateOperator(String operatorIdentifier) {
756 String newName = operatorNameMap[operatorIdentifier];
757 if (newName == null) {
758 newName = getFreshName(operatorIdentifier, usedInstanceNames,
588 suggestedInstanceNames, ensureSafe: false); 759 suggestedInstanceNames, ensureSafe: false);
589 operatorNameMap[proposedName] = newName; 760 operatorNameMap[operatorIdentifier] = newName;
590 } 761 }
591 return newName; 762 return newName;
592 } 763 }
593 764
765 /// Returns an unused name.
766 ///
767 /// [proposedName] must be a valid JavaScript identifier.
768 ///
769 /// If [ensureSafe] is `false`, then [proposedName] must not be a keyword.
770 ///
771 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not
772 /// to have the form of an annotated name.
773 ///
774 /// Note that [MinifyNamer] overrides this method with one that produces
775 /// minified names.
594 String getFreshName(String proposedName, 776 String getFreshName(String proposedName,
595 Set<String> usedNames, 777 Set<String> usedNames,
596 Map<String, String> suggestedNames, 778 Map<String, String> suggestedNames,
597 {bool ensureSafe: true}) { 779 {bool ensureSafe: true,
598 var candidate; 780 bool sanitizeForAnnotations: false}) {
781 if (sanitizeForAnnotations) {
782 proposedName = _sanitizeForAnnotations(proposedName);
783 }
599 if (ensureSafe) { 784 if (ensureSafe) {
600 proposedName = safeName(proposedName); 785 proposedName = safeName(proposedName);
601 } 786 }
602 assert(!jsReserved.contains(proposedName)); 787 assert(!jsReserved.contains(proposedName));
788 String candidate;
603 if (!usedNames.contains(proposedName)) { 789 if (!usedNames.contains(proposedName)) {
604 candidate = proposedName; 790 candidate = proposedName;
605 } else { 791 } else {
606 var counter = popularNameCounters[proposedName]; 792 int counter = popularNameCounters[proposedName];
607 var i = counter == null ? 0 : counter; 793 int i = counter == null ? 0 : counter;
608 while (usedNames.contains("$proposedName$i")) { 794 while (usedNames.contains("$proposedName$i")) {
609 i++; 795 i++;
610 } 796 }
611 popularNameCounters[proposedName] = i + 1; 797 popularNameCounters[proposedName] = i + 1;
612 candidate = "$proposedName$i"; 798 candidate = "$proposedName$i";
613 } 799 }
614 usedNames.add(candidate); 800 usedNames.add(candidate);
615 return candidate; 801 return candidate;
616 } 802 }
617 803
804 /// Returns a variant of [name] that cannot clash with the annotated
805 /// version of another name, that is, the resulting name can never be returned
806 /// by [deriveGetterName], [deriveSetterName], [deriveMethodName],
807 /// [operatorIs], or [substitutionName].
808 ///
809 /// For example, a name `get$x` would be converted to `$get$x` to ensure it
810 /// does cannot clash with the getter for `x`.
811 ///
812 /// We don't want to register all potential annotated names in
813 /// [usedInstanceNames] (there are too many), so we use this step to avoid
814 /// clashes between annotated and unannotated names.
815 String _sanitizeForAnnotations(String name) {
816 // Ensure name does not contain a $ followed by a digit, since this could
817 // clash with the suffix we append on method names.
818 for (int i = name.indexOf(r'$'); i != -1; i = name.indexOf(r'$', i+1)) {
819 if (i + 1 < name.length && isDigit(name.codeUnitAt(i+1))) {
820 // Strip off everything after the $ to be safe.
821 name = name.substring(0, i + 1);
822 break;
823 }
824 }
825 // Ensure name does not clash with a getter or setter of another name, or
826 // one of the other special names that start with `$`, such as `$is`.
827 if (name.startsWith(r'$') ||
828 name.startsWith(getterPrefix) ||
829 name.startsWith(setterPrefix)) {
830 name = '\$$name';
831 }
832 return name;
833 }
834
618 String getClosureVariableName(String name, int id) { 835 String getClosureVariableName(String name, int id) {
619 return "${name}_$id"; 836 return "${name}_$id";
620 } 837 }
621 838
622 /** 839 /**
623 * Returns a preferred JS-id for the given top-level or static element. 840 * Returns a proposed name for the given top-level or static element.
624 * The returned id is guaranteed to be a valid JS-id. 841 * The returned id is guaranteed to be a valid JS-id.
625 */ 842 */
626 String _computeGuess(Element element) { 843 String _proposeNameForGlobal(Element element) {
627 assert(!element.isInstanceMember); 844 assert(!element.isInstanceMember);
628 String name; 845 String name;
629 if (element.isGenerativeConstructor) { 846 if (element.isGenerativeConstructor) {
630 name = "${element.enclosingClass.name}\$" 847 name = "${element.enclosingClass.name}\$"
631 "${element.name}"; 848 "${element.name}";
632 } else if (element.isFactoryConstructor) { 849 } else if (element.isFactoryConstructor) {
633 // TODO(johnniwinther): Change factory name encoding as to not include 850 // TODO(johnniwinther): Change factory name encoding as to not include
634 // the class-name twice. 851 // the class-name twice.
635 String className = element.enclosingClass.name; 852 String className = element.enclosingClass.name;
636 name = '${className}_${Elements.reconstructConstructorName(element)}'; 853 name = '${className}_${Elements.reconstructConstructorName(element)}';
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
688 // There is one dispatch mechanism for all native classes. 905 // There is one dispatch mechanism for all native classes.
689 if (classes.any((cls) => Elements.isNativeOrExtendsNative(cls))) { 906 if (classes.any((cls) => Elements.isNativeOrExtendsNative(cls))) {
690 names.add("x"); 907 names.add("x");
691 } 908 }
692 // Sort the names of the classes after abbreviating them to ensure 909 // Sort the names of the classes after abbreviating them to ensure
693 // the suffix is stable and predictable for the suggested names. 910 // the suffix is stable and predictable for the suggested names.
694 names.sort(); 911 names.sort();
695 return names.join(); 912 return names.join();
696 } 913 }
697 914
698 String getInterceptorName(Element element, Iterable<ClassElement> classes) { 915 /// Property name used for `getInterceptor` or one of its specializations.
916 String getInterceptorName(Iterable<ClassElement> classes) {
917 FunctionElement getInterceptor = backend.getInterceptorMethod;
699 if (classes.contains(backend.jsInterceptorClass)) { 918 if (classes.contains(backend.jsInterceptorClass)) {
700 // If the base Interceptor class is in the set of intercepted classes, we 919 // If the base Interceptor class is in the set of intercepted classes, we
701 // need to go through the generic getInterceptorMethod, since any subclass 920 // need to go through the generic getInterceptorMethod, since any subclass
702 // of the base Interceptor could match. 921 // of the base Interceptor could match.
703 return getNameOfInstanceMember(element); 922 // The unspecialized getInterceptor method can also be accessed through
923 // its element, so we treat this as a user-space global instead of an
924 // intern global.
925 return disambiguateGlobal(getInterceptor);
704 } 926 }
705 String suffix = getInterceptorSuffix(classes); 927 String suffix = getInterceptorSuffix(classes);
706 return getMappedGlobalName("${element.name}\$$suffix"); 928 return disambiguateInternGlobal("${getInterceptor.name}\$$suffix");
707 } 929 }
708 930
931 /// Property name used for the one-shot interceptor method for the given
932 /// [selector] and return-type specialization.
709 String getOneShotInterceptorName(Selector selector, 933 String getOneShotInterceptorName(Selector selector,
710 Iterable<ClassElement> classes) { 934 Iterable<ClassElement> classes) {
711 // The one-shot name is a global name derived from the invocation name. To 935 // The one-shot name is a global name derived from the invocation name. To
712 // avoid instability we would like the names to be unique and not clash with 936 // avoid instability we would like the names to be unique and not clash with
713 // other global names. 937 // other global names.
714 938
715 String root = invocationName(selector); // Is already safe. 939 String root = invocationName(selector); // Is already safe.
716 940
717 if (classes.contains(backend.jsInterceptorClass)) { 941 if (classes.contains(backend.jsInterceptorClass)) {
718 // If the base Interceptor class is in the set of intercepted classes, 942 // If the base Interceptor class is in the set of intercepted classes,
719 // this is the most general specialization which uses the generic 943 // this is the most general specialization which uses the generic
720 // getInterceptor method. To keep the name short, we add '$' only to 944 // getInterceptor method. To keep the name short, we add '$' only to
721 // distinguish from global getters or setters; operators and methods can't 945 // distinguish from other intern globals that don't contain '$' symbols.
722 // clash.
723 // TODO(sra): Find a way to get the simple name when Object is not in the 946 // TODO(sra): Find a way to get the simple name when Object is not in the
724 // set of classes for most general variant, e.g. "$lt$n" could be "$lt". 947 // set of classes for most general variant, e.g. "$lt$n" could be "$lt".
725 if (selector.isGetter || selector.isSetter) root = '$root\$'; 948 if (selector.isGetter || selector.isSetter) root = '$root\$';
726 return getMappedGlobalName(root, ensureSafe: false); 949 return disambiguateInternGlobal(root, ensureSafe: false);
727 } else { 950 } else {
728 String suffix = getInterceptorSuffix(classes); 951 String suffix = getInterceptorSuffix(classes);
729 return getMappedGlobalName("$root\$$suffix", ensureSafe: false); 952 return disambiguateInternGlobal("$root\$$suffix", ensureSafe: false);
730 } 953 }
731 } 954 }
732 955
733 /// Returns the runtime name for [element]. The result is not safe as an id. 956 /// Returns the runtime name for [element].
734 String getRuntimeTypeName(Element element) { 957 ///
958 /// This name is used as the basis for deriving `is` and `as` property names
959 /// for the given type.
960 ///
961 /// The result is not always safe as a property name unless prefixing
962 /// [operatorIsPrefix] or [operatorAsPrefix]. If this is a function type,
963 /// then by convention, an underscore must also separate [operatorIsPrefix]
964 /// from the type name.
965 String getRuntimeTypeName(TypeDeclarationElement element) {
735 if (element == null) return 'dynamic'; 966 if (element == null) return 'dynamic';
736 return getNameForRti(element); 967 // The returned name affects both the global and instance member namespaces:
968 //
969 // - If given a class, this must coincide with the class name, which
970 // is also the GLOBAL property name of its constructor.
971 //
972 // - The result is used to derive `$isX` and `$asX` names, which are used
973 // as INSTANCE property names.
974 //
975 // To prevent clashes in both namespaces at once, we disambiguate the name
976 // as a global here, and in [_sanitizeForAnnotations] we ensure that
977 // ordinary instance members cannot start with a '$' character.
978 return disambiguateGlobal(element);
737 } 979 }
738 980
739 /** 981 /// Returns the disambiguated name of [class_].
740 * Returns a preferred JS-id for the given element. The returned id is 982 ///
741 * guaranteed to be a valid JS-id. Globals and static fields are furthermore 983 /// This is both the *runtime type* of the class (see [getRuntimeTypeName])
742 * guaranteed to be unique. 984 /// and a global property name in which to store its JS constructor.
743 * 985 String getNameOfClass(ClassElement class_) => disambiguateGlobal(class_);
744 * For accessing statics consider calling [elementAccess] instead.
745 */
746 // TODO(ahe): This is an internal method to the Namer (and its subclasses)
747 // and should not be call from outside.
748 String getNameX(Element element) {
749 if (element.isInstanceMember) {
750 if (element.kind == ElementKind.GENERATIVE_CONSTRUCTOR_BODY
751 || element.kind == ElementKind.FUNCTION) {
752 return instanceMethodName(element);
753 } else if (element.kind == ElementKind.GETTER) {
754 return getterName(element);
755 } else if (element.kind == ElementKind.SETTER) {
756 return setterName(element);
757 } else if (element.kind == ElementKind.FIELD) {
758 compiler.internalError(element,
759 'Use instanceFieldPropertyName or instanceFieldAccessorName.');
760 return null;
761 } else {
762 compiler.internalError(element,
763 'getName for bad kind: ${element.kind}.');
764 return null;
765 }
766 } else {
767 // Use declaration element to ensure invariant on [globals].
768 element = element.declaration;
769 // Dealing with a top-level or static element.
770 String cached = globals[element];
771 if (cached != null) return cached;
772 986
773 String guess = _computeGuess(element); 987 /// Property name on which [member] can be accessed directly,
774 ElementKind kind = element.kind; 988 /// without clashing with another JS property name.
775 if (kind == ElementKind.VARIABLE || 989 String getNameOfAliasedSuperMember(Element member) {
776 kind == ElementKind.PARAMETER) { 990 assert(!member.isField); // Fields do not need super aliases.
777 // The name is not guaranteed to be unique. 991 return disambiguateDirectAccess(member,
778 return safeName(guess); 992 () => '\$super\$${member.enclosingClass.name}\$${member.name}');
779 }
780 if (kind == ElementKind.GENERATIVE_CONSTRUCTOR ||
781 kind == ElementKind.FUNCTION ||
782 kind == ElementKind.CLASS ||
783 kind == ElementKind.FIELD ||
784 kind == ElementKind.GETTER ||
785 kind == ElementKind.SETTER ||
786 kind == ElementKind.TYPEDEF ||
787 kind == ElementKind.LIBRARY) {
788 bool fixedName = false;
789 if (Elements.isInstanceField(element)) {
790 fixedName = element.hasFixedBackendName;
791 }
792 String result = fixedName
793 ? guess
794 : getFreshName(guess, usedGlobalNames, suggestedGlobalNames,
795 ensureSafe: true);
796 globals[element] = result;
797 return result;
798 }
799 compiler.internalError(element,
800 'getName for unknown kind: ${element.kind}.');
801 return null;
802 }
803 } 993 }
804 994
805 String getNameForRti(Element element) => getNameX(element); 995 /// Property name in which to store the given static or instance [method].
806 996 /// For instance methods, this includes the suffix encoding arity and named
807 String getNameOfLibrary(LibraryElement library) => getNameX(library); 997 /// parameters.
808 998 ///
809 String getNameOfClass(ClassElement cls) => getNameX(cls); 999 /// The name is not necessarily unique to [method], since a static method
810 1000 /// may share its name with an instance method.
811 String getNameOfField(VariableElement field) => getNameX(field); 1001 String getNameOfMethod(Element method) {
812 1002 return method.isInstanceMember
813 // TODO(ahe): Remove this method. Use get getNameOfMember instead. 1003 ? instanceMethodName(method)
814 String getNameOfInstanceMember(Element member) => getNameX(member); 1004 : globalPropertyName(method);
815
816 String getNameOfAliasedSuperMember(Element member) {
817 ClassElement superClass = member.enclosingClass;
818 String className = getNameOfClass(superClass);
819 String memberName = getNameOfMember(member);
820 String proposal = "$superPrefix$className\$$memberName";
821 // TODO(herhut): Use field naming constraints (unique wrt. inheritance).
822 return getMappedInstanceName(proposal);
823 } 1005 }
824 1006
825 String getNameOfMember(Element member) => getNameX(member);
826
827 String getNameOfGlobalField(VariableElement field) => getNameX(field);
828
829 /// Returns true if [element] is stored on current isolate ('$'). We intend 1007 /// Returns true if [element] is stored on current isolate ('$'). We intend
830 /// to store only mutable static state in [currentIsolate], constants are 1008 /// to store only mutable static state in [currentIsolate], constants are
831 /// stored in 'C', and functions, accessors, classes, etc. are stored in one 1009 /// stored in 'C', and functions, accessors, classes, etc. are stored in one
832 /// of the other objects in [reservedGlobalObjectNames]. 1010 /// of the other objects in [reservedGlobalObjectNames].
833 bool isPropertyOfCurrentIsolate(Element element) { 1011 bool isPropertyOfCurrentIsolate(Element element) {
834 // TODO(ahe): Make sure this method's documentation is always true and 1012 // TODO(ahe): Make sure this method's documentation is always true and
835 // remove the word "intend". 1013 // remove the word "intend".
836 return 1014 return
837 // TODO(ahe): Re-write these tests to be positive (so it only returns 1015 // TODO(ahe): Re-write these tests to be positive (so it only returns
838 // true for static/top-level mutable fields). Right now, a number of 1016 // true for static/top-level mutable fields). Right now, a number of
(...skipping 15 matching lines...) Expand all
854 if (library.isPlatformLibrary) { 1032 if (library.isPlatformLibrary) {
855 if ('${library.canonicalUri}' == 'dart:html') return 'W'; 1033 if ('${library.canonicalUri}' == 'dart:html') return 'W';
856 return 'P'; 1034 return 'P';
857 } 1035 }
858 return userGlobalObjects[ 1036 return userGlobalObjects[
859 library.getLibraryOrScriptName().hashCode % userGlobalObjects.length]; 1037 library.getLibraryOrScriptName().hashCode % userGlobalObjects.length];
860 } 1038 }
861 1039
862 String getLazyInitializerName(Element element) { 1040 String getLazyInitializerName(Element element) {
863 assert(Elements.isStaticOrTopLevelField(element)); 1041 assert(Elements.isStaticOrTopLevelField(element));
864 return getMappedGlobalName("$getterPrefix${getNameX(element)}"); 1042 return disambiguateInternGlobal("$getterPrefix${globalPropertyName(element)} ");
865 } 1043 }
866 1044
867 String getStaticClosureName(Element element) { 1045 String getStaticClosureName(Element element) {
868 assert(Elements.isStaticOrTopLevelFunction(element)); 1046 assert(Elements.isStaticOrTopLevelFunction(element));
869 return getMappedGlobalName("${getNameX(element)}\$closure"); 1047 return disambiguateInternGlobal("${globalPropertyName(element)}\$closure");
870 } 1048 }
871 1049
872 // This name is used as part of the name of a TypeConstant 1050 // This name is used as part of the name of a TypeConstant
873 String uniqueNameForTypeConstantElement(Element element) { 1051 String uniqueNameForTypeConstantElement(Element element) {
874 // TODO(sra): If we replace the period with an identifier character, 1052 // TODO(sra): If we replace the period with an identifier character,
875 // TypeConstants will have better names in unminified code. 1053 // TypeConstants will have better names in unminified code.
876 return "${globalObjectFor(element)}.${getNameX(element)}"; 1054 return "${globalObjectFor(element)}.${globalPropertyName(element)}";
877 } 1055 }
878 1056
879 String globalObjectForConstant(ConstantValue constant) => 'C'; 1057 String globalObjectForConstant(ConstantValue constant) => 'C';
880 1058
881 String get operatorIsPrefix => r'$is'; 1059 String get operatorIsPrefix => r'$is';
882 1060
883 String get operatorAsPrefix => r'$as'; 1061 String get operatorAsPrefix => r'$as';
884 1062
885 String get operatorSignature => r'$signature'; 1063 String get operatorSignature => r'$signature';
886 1064
(...skipping 25 matching lines...) Expand all
912 } 1090 }
913 1091
914 String operatorIsType(DartType type) { 1092 String operatorIsType(DartType type) {
915 if (type.isFunctionType) { 1093 if (type.isFunctionType) {
916 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. 1094 // TODO(erikcorry): Reduce from $isx to ix when we are minifying.
917 return '${operatorIsPrefix}_${getFunctionTypeName(type)}'; 1095 return '${operatorIsPrefix}_${getFunctionTypeName(type)}';
918 } 1096 }
919 return operatorIs(type.element); 1097 return operatorIs(type.element);
920 } 1098 }
921 1099
922 String operatorIs(Element element) { 1100 String operatorIs(ClassElement element) {
923 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. 1101 // TODO(erikcorry): Reduce from $isx to ix when we are minifying.
924 return '${operatorIsPrefix}${getRuntimeTypeName(element)}'; 1102 return '${operatorIsPrefix}${getRuntimeTypeName(element)}';
925 } 1103 }
926 1104
927 /* 1105 /*
928 * Returns a name that does not clash with reserved JS keywords, 1106 * Returns a name that does not clash with reserved JS keywords,
929 * and also ensures it won't clash with other identifiers. 1107 * and also ensures it won't clash with other identifiers.
930 */ 1108 */
931 String _safeName(String name, Set<String> reserved) { 1109 String _safeName(String name, Set<String> reserved) {
932 if (reserved.contains(name) || name.startsWith(r'$')) { 1110 if (reserved.contains(name)) {
933 name = '\$$name'; 1111 name = '\$$name';
934 } 1112 }
935 assert(!reserved.contains(name)); 1113 assert(!reserved.contains(name));
936 return name; 1114 return name;
937 } 1115 }
938 1116
939 String substitutionName(Element element) { 1117 String substitutionName(Element element) {
940 // TODO(ahe): Creating a string here is unfortunate. It is slow (due to 1118 // TODO(ahe): Creating a string here is unfortunate. It is slow (due to
941 // string concatenation in the implementation), and may prevent 1119 // string concatenation in the implementation), and may prevent
942 // segmentation of '$'. 1120 // segmentation of '$'.
943 return '${operatorAsPrefix}${getNameForRti(element)}'; 1121 return '${operatorAsPrefix}${getRuntimeTypeName(element)}';
944 } 1122 }
945 1123
946 String safeName(String name) => _safeName(name, jsReserved); 1124 String safeName(String name) => _safeName(name, jsReserved);
947 String safeVariableName(String name) => _safeName(name, jsVariableReserved); 1125 String safeVariableName(String name) => _safeName(name, jsVariableReserved);
948 1126
949 String operatorNameToIdentifier(String name) { 1127 String operatorNameToIdentifier(String name) {
950 if (name == null) return null; 1128 if (name == null) return null;
951 if (name == '==') { 1129 if (name == '==') {
952 return r'$eq'; 1130 return r'$eq';
953 } else if (name == '~') { 1131 } else if (name == '~') {
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
1416 if (!first) { 1594 if (!first) {
1417 sb.write('_'); 1595 sb.write('_');
1418 } 1596 }
1419 sb.write('_'); 1597 sb.write('_');
1420 visit(parameter); 1598 visit(parameter);
1421 first = true; 1599 first = true;
1422 } 1600 }
1423 } 1601 }
1424 } 1602 }
1425 } 1603 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698