OLD | NEW |
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 * Names are generated through three stages: | 10 * Names are generated through three stages: |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 * | 95 * |
96 * 3. The `is` and operator uses the following names: | 96 * 3. The `is` and operator uses the following names: |
97 * | 97 * |
98 * $is<NAME> | 98 * $is<NAME> |
99 * $as<NAME> | 99 * $as<NAME> |
100 * | 100 * |
101 * For local variables, the [Namer] only provides *proposed names*. These names | 101 * For local variables, the [Namer] only provides *proposed names*. These names |
102 * must be disambiguated elsewhere. | 102 * must be disambiguated elsewhere. |
103 */ | 103 */ |
104 class Namer { | 104 class Namer { |
105 | |
106 static const List<String> javaScriptKeywords = const <String>[ | 105 static const List<String> javaScriptKeywords = const <String>[ |
107 // These are current keywords. | 106 // These are current keywords. |
108 "break", "delete", "function", "return", "typeof", "case", "do", "if", | 107 "break", "delete", "function", "return", "typeof", "case", "do", "if", |
109 "switch", "var", "catch", "else", "in", "this", "void", "continue", | 108 "switch", "var", "catch", "else", "in", "this", "void", "continue", |
110 "false", "instanceof", "throw", "while", "debugger", "finally", "new", | 109 "false", "instanceof", "throw", "while", "debugger", "finally", "new", |
111 "true", "with", "default", "for", "null", "try", | 110 "true", "with", "default", "for", "null", "try", |
112 | 111 |
113 // These are future keywords. | 112 // These are future keywords. |
114 "abstract", "double", "goto", "native", "static", "boolean", "enum", | 113 "abstract", "double", "goto", "native", "static", "boolean", "enum", |
115 "implements", "package", "super", "byte", "export", "import", "private", | 114 "implements", "package", "super", "byte", "export", "import", "private", |
116 "synchronized", "char", "extends", "int", "protected", "throws", | 115 "synchronized", "char", "extends", "int", "protected", "throws", |
117 "class", "final", "interface", "public", "transient", "const", "float", | 116 "class", "final", "interface", "public", "transient", "const", "float", |
118 "long", "short", "volatile" | 117 "long", "short", "volatile" |
119 ]; | 118 ]; |
120 | 119 |
121 static const List<String> reservedPropertySymbols = | 120 static const List<String> reservedPropertySymbols = const <String>[ |
122 const <String>[ | 121 "__proto__", "prototype", "constructor", "call", |
123 "__proto__", "prototype", "constructor", "call", | 122 // "use strict" disallows the use of "arguments" and "eval" as |
124 // "use strict" disallows the use of "arguments" and "eval" as | 123 // variable names or property names. See ECMA-262, Edition 5.1, |
125 // variable names or property names. See ECMA-262, Edition 5.1, | 124 // section 11.1.5 (for the property names). |
126 // section 11.1.5 (for the property names). | 125 "eval", "arguments" |
127 "eval", "arguments"]; | 126 ]; |
128 | 127 |
129 // Symbols that we might be using in our JS snippets. | 128 // Symbols that we might be using in our JS snippets. |
130 static const List<String> reservedGlobalSymbols = const <String>[ | 129 static const List<String> reservedGlobalSymbols = const <String>[ |
131 // Section references are from Ecma-262 | 130 // Section references are from Ecma-262 |
132 // (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pd
f) | 131 // (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pd
f) |
133 | 132 |
134 // 15.1.1 Value Properties of the Global Object | 133 // 15.1.1 Value Properties of the Global Object |
135 "NaN", "Infinity", "undefined", | 134 "NaN", "Infinity", "undefined", |
136 | 135 |
137 // 15.1.2 Function Properties of the Global Object | 136 // 15.1.2 Function Properties of the Global Object |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 // These keywords trigger the loading of the java-plugin. For the | 243 // These keywords trigger the loading of the java-plugin. For the |
245 // next-generation plugin, this results in starting a new Java process. | 244 // next-generation plugin, this results in starting a new Java process. |
246 "java", "Packages", "netscape", "sun", "JavaObject", "JavaClass", | 245 "java", "Packages", "netscape", "sun", "JavaObject", "JavaClass", |
247 "JavaArray", "JavaMember", | 246 "JavaArray", "JavaMember", |
248 | 247 |
249 // ES6 collections. | 248 // ES6 collections. |
250 "Map", | 249 "Map", |
251 ]; | 250 ]; |
252 | 251 |
253 static const List<String> reservedGlobalObjectNames = const <String>[ | 252 static const List<String> reservedGlobalObjectNames = const <String>[ |
254 "A", | 253 "A", |
255 "B", | 254 "B", |
256 "C", // Global object for *C*onstants. | 255 "C", // Global object for *C*onstants. |
257 "D", | 256 "D", |
258 "E", | 257 "E", |
259 "F", | 258 "F", |
260 "G", | 259 "G", |
261 "H", // Global object for internal (*H*elper) libraries. | 260 "H", // Global object for internal (*H*elper) libraries. |
262 // I is used for used for the Isolate function. | 261 // I is used for used for the Isolate function. |
263 "J", // Global object for the interceptor library. | 262 "J", // Global object for the interceptor library. |
264 "K", | 263 "K", |
265 "L", | 264 "L", |
266 "M", | 265 "M", |
267 "N", | 266 "N", |
268 "O", | 267 "O", |
269 "P", // Global object for other *P*latform libraries. | 268 "P", // Global object for other *P*latform libraries. |
270 "Q", | 269 "Q", |
271 "R", | 270 "R", |
272 "S", | 271 "S", |
273 "T", | 272 "T", |
274 "U", | 273 "U", |
275 "V", | 274 "V", |
276 "W", // Global object for *W*eb libraries (dart:html). | 275 "W", // Global object for *W*eb libraries (dart:html). |
277 "X", | 276 "X", |
278 "Y", | 277 "Y", |
279 "Z", | 278 "Z", |
280 ]; | 279 ]; |
281 | 280 |
282 static const List<String> reservedGlobalHelperFunctions = const <String>[ | 281 static const List<String> reservedGlobalHelperFunctions = const <String>[ |
283 "init", | 282 "init", |
284 "Isolate", | 283 "Isolate", |
285 ]; | 284 ]; |
286 | 285 |
287 static final List<String> userGlobalObjects = | 286 static final List<String> userGlobalObjects = |
288 new List.from(reservedGlobalObjectNames) | 287 new List.from(reservedGlobalObjectNames) |
289 ..remove('C') | 288 ..remove('C') |
290 ..remove('H') | 289 ..remove('H') |
291 ..remove('J') | 290 ..remove('J') |
292 ..remove('P') | 291 ..remove('P') |
293 ..remove('W'); | 292 ..remove('W'); |
294 | 293 |
295 Set<String> _jsReserved = null; | 294 Set<String> _jsReserved = null; |
| 295 |
296 /// Names that cannot be used by members, top level and static | 296 /// Names that cannot be used by members, top level and static |
297 /// methods. | 297 /// methods. |
298 Set<String> get jsReserved { | 298 Set<String> get jsReserved { |
299 if (_jsReserved == null) { | 299 if (_jsReserved == null) { |
300 _jsReserved = new Set<String>(); | 300 _jsReserved = new Set<String>(); |
301 _jsReserved.addAll(javaScriptKeywords); | 301 _jsReserved.addAll(javaScriptKeywords); |
302 _jsReserved.addAll(reservedPropertySymbols); | 302 _jsReserved.addAll(reservedPropertySymbols); |
303 } | 303 } |
304 return _jsReserved; | 304 return _jsReserved; |
305 } | 305 } |
306 | 306 |
307 Set<String> _jsVariableReserved = null; | 307 Set<String> _jsVariableReserved = null; |
| 308 |
308 /// Names that cannot be used by local variables and parameters. | 309 /// Names that cannot be used by local variables and parameters. |
309 Set<String> get jsVariableReserved { | 310 Set<String> get jsVariableReserved { |
310 if (_jsVariableReserved == null) { | 311 if (_jsVariableReserved == null) { |
311 _jsVariableReserved = new Set<String>(); | 312 _jsVariableReserved = new Set<String>(); |
312 _jsVariableReserved.addAll(javaScriptKeywords); | 313 _jsVariableReserved.addAll(javaScriptKeywords); |
313 _jsVariableReserved.addAll(reservedPropertySymbols); | 314 _jsVariableReserved.addAll(reservedPropertySymbols); |
314 _jsVariableReserved.addAll(reservedGlobalSymbols); | 315 _jsVariableReserved.addAll(reservedGlobalSymbols); |
315 _jsVariableReserved.addAll(reservedGlobalObjectNames); | 316 _jsVariableReserved.addAll(reservedGlobalObjectNames); |
316 // 26 letters in the alphabet, 25 not counting I. | 317 // 26 letters in the alphabet, 25 not counting I. |
317 assert(reservedGlobalObjectNames.length == 25); | 318 assert(reservedGlobalObjectNames.length == 25); |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 | 450 |
450 /** | 451 /** |
451 * Some closures must contain their name. The name is stored in | 452 * Some closures must contain their name. The name is stored in |
452 * [STATIC_CLOSURE_NAME_NAME]. | 453 * [STATIC_CLOSURE_NAME_NAME]. |
453 */ | 454 */ |
454 String get STATIC_CLOSURE_NAME_NAME => r'$name'; | 455 String get STATIC_CLOSURE_NAME_NAME => r'$name'; |
455 String get closureInvocationSelectorName => Identifiers.call; | 456 String get closureInvocationSelectorName => Identifiers.call; |
456 bool get shouldMinify => false; | 457 bool get shouldMinify => false; |
457 | 458 |
458 NamingScope _getPrivateScopeFor(PrivatelyNamedJSEntity entity) { | 459 NamingScope _getPrivateScopeFor(PrivatelyNamedJSEntity entity) { |
459 return _privateNamingScopes.putIfAbsent(entity.rootOfScope, | 460 return _privateNamingScopes.putIfAbsent( |
460 () => new NamingScope()); | 461 entity.rootOfScope, () => new NamingScope()); |
461 } | 462 } |
462 | 463 |
463 /// Returns the string that is to be used as the result of a call to | 464 /// Returns the string that is to be used as the result of a call to |
464 /// [JS_GET_NAME] at [node] with argument [name]. | 465 /// [JS_GET_NAME] at [node] with argument [name]. |
465 jsAst.Name getNameForJsGetName(Node node, JsGetName name) { | 466 jsAst.Name getNameForJsGetName(Node node, JsGetName name) { |
466 switch (name) { | 467 switch (name) { |
467 case JsGetName.GETTER_PREFIX: return asName(getterPrefix); | 468 case JsGetName.GETTER_PREFIX: |
468 case JsGetName.SETTER_PREFIX: return asName(setterPrefix); | 469 return asName(getterPrefix); |
469 case JsGetName.CALL_PREFIX: return asName(callPrefix); | 470 case JsGetName.SETTER_PREFIX: |
470 case JsGetName.CALL_PREFIX0: return asName('${callPrefix}\$0'); | 471 return asName(setterPrefix); |
471 case JsGetName.CALL_PREFIX1: return asName('${callPrefix}\$1'); | 472 case JsGetName.CALL_PREFIX: |
472 case JsGetName.CALL_PREFIX2: return asName('${callPrefix}\$2'); | 473 return asName(callPrefix); |
473 case JsGetName.CALL_PREFIX3: return asName('${callPrefix}\$3'); | 474 case JsGetName.CALL_PREFIX0: |
474 case JsGetName.CALL_CATCH_ALL: return asName(callCatchAllName); | 475 return asName('${callPrefix}\$0'); |
475 case JsGetName.REFLECTABLE: return asName(reflectableField); | 476 case JsGetName.CALL_PREFIX1: |
| 477 return asName('${callPrefix}\$1'); |
| 478 case JsGetName.CALL_PREFIX2: |
| 479 return asName('${callPrefix}\$2'); |
| 480 case JsGetName.CALL_PREFIX3: |
| 481 return asName('${callPrefix}\$3'); |
| 482 case JsGetName.CALL_CATCH_ALL: |
| 483 return asName(callCatchAllName); |
| 484 case JsGetName.REFLECTABLE: |
| 485 return asName(reflectableField); |
476 case JsGetName.CLASS_DESCRIPTOR_PROPERTY: | 486 case JsGetName.CLASS_DESCRIPTOR_PROPERTY: |
477 return asName(classDescriptorProperty); | 487 return asName(classDescriptorProperty); |
478 case JsGetName.REQUIRED_PARAMETER_PROPERTY: | 488 case JsGetName.REQUIRED_PARAMETER_PROPERTY: |
479 return asName(requiredParameterField); | 489 return asName(requiredParameterField); |
480 case JsGetName.DEFAULT_VALUES_PROPERTY: return asName(defaultValuesField); | 490 case JsGetName.DEFAULT_VALUES_PROPERTY: |
481 case JsGetName.CALL_NAME_PROPERTY: return asName(callNameField); | 491 return asName(defaultValuesField); |
482 case JsGetName.DEFERRED_ACTION_PROPERTY: return asName(deferredAction); | 492 case JsGetName.CALL_NAME_PROPERTY: |
483 case JsGetName.OPERATOR_AS_PREFIX: return asName(operatorAsPrefix); | 493 return asName(callNameField); |
484 case JsGetName.SIGNATURE_NAME: return asName(operatorSignature); | 494 case JsGetName.DEFERRED_ACTION_PROPERTY: |
485 case JsGetName.TYPEDEF_TAG: return asName(typedefTag); | 495 return asName(deferredAction); |
| 496 case JsGetName.OPERATOR_AS_PREFIX: |
| 497 return asName(operatorAsPrefix); |
| 498 case JsGetName.SIGNATURE_NAME: |
| 499 return asName(operatorSignature); |
| 500 case JsGetName.TYPEDEF_TAG: |
| 501 return asName(typedefTag); |
486 case JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG: | 502 case JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG: |
487 return asName(functionTypeVoidReturnTag); | 503 return asName(functionTypeVoidReturnTag); |
488 case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG: | 504 case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG: |
489 return asName(functionTypeReturnTypeTag); | 505 return asName(functionTypeReturnTypeTag); |
490 case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG: | 506 case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG: |
491 return asName(functionTypeRequiredParametersTag); | 507 return asName(functionTypeRequiredParametersTag); |
492 case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG: | 508 case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG: |
493 return asName(functionTypeOptionalParametersTag); | 509 return asName(functionTypeOptionalParametersTag); |
494 case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG: | 510 case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG: |
495 return asName(functionTypeNamedParametersTag); | 511 return asName(functionTypeNamedParametersTag); |
496 case JsGetName.IS_INDEXABLE_FIELD_NAME: | 512 case JsGetName.IS_INDEXABLE_FIELD_NAME: |
497 return operatorIs(helpers.jsIndexingBehaviorInterface); | 513 return operatorIs(helpers.jsIndexingBehaviorInterface); |
498 case JsGetName.NULL_CLASS_TYPE_NAME: | 514 case JsGetName.NULL_CLASS_TYPE_NAME: |
499 return runtimeTypeName(coreClasses.nullClass); | 515 return runtimeTypeName(coreClasses.nullClass); |
500 case JsGetName.OBJECT_CLASS_TYPE_NAME: | 516 case JsGetName.OBJECT_CLASS_TYPE_NAME: |
501 return runtimeTypeName(coreClasses.objectClass); | 517 return runtimeTypeName(coreClasses.objectClass); |
502 case JsGetName.FUNCTION_CLASS_TYPE_NAME: | 518 case JsGetName.FUNCTION_CLASS_TYPE_NAME: |
503 return runtimeTypeName(coreClasses.functionClass); | 519 return runtimeTypeName(coreClasses.functionClass); |
504 default: | 520 default: |
505 reporter.reportErrorMessage( | 521 reporter.reportErrorMessage(node, MessageKind.GENERIC, |
506 node, | 522 {'text': 'Error: Namer has no name for "$name".'}); |
507 MessageKind.GENERIC, | |
508 {'text': 'Error: Namer has no name for "$name".'}); | |
509 return asName('BROKEN'); | 523 return asName('BROKEN'); |
510 } | 524 } |
511 } | 525 } |
512 | 526 |
513 /// Return a reference to the given [name]. | 527 /// Return a reference to the given [name]. |
514 /// | 528 /// |
515 /// This is used to ensure that every use site of a name has a unique node so | 529 /// This is used to ensure that every use site of a name has a unique node so |
516 /// that we can properly attribute source information. | 530 /// that we can properly attribute source information. |
517 jsAst.Name _newReference(jsAst.Name name) { | 531 jsAst.Name _newReference(jsAst.Name name) { |
518 return new _NameReference(name); | 532 return new _NameReference(name); |
(...skipping 13 matching lines...) Expand all Loading... |
532 result = getFreshName(constantScope, longName); | 546 result = getFreshName(constantScope, longName); |
533 constantNames[constant] = result; | 547 constantNames[constant] = result; |
534 } | 548 } |
535 return _newReference(result); | 549 return _newReference(result); |
536 } | 550 } |
537 | 551 |
538 /// Proposed name for [constant]. | 552 /// Proposed name for [constant]. |
539 String constantLongName(ConstantValue constant) { | 553 String constantLongName(ConstantValue constant) { |
540 String longName = constantLongNames[constant]; | 554 String longName = constantLongNames[constant]; |
541 if (longName == null) { | 555 if (longName == null) { |
542 longName = new ConstantNamingVisitor(compiler, constantHasher) | 556 longName = |
543 .getName(constant); | 557 new ConstantNamingVisitor(compiler, constantHasher).getName(constant); |
544 constantLongNames[constant] = longName; | 558 constantLongNames[constant] = longName; |
545 } | 559 } |
546 return longName; | 560 return longName; |
547 } | 561 } |
548 | 562 |
549 String breakLabelName(LabelDefinition label) { | 563 String breakLabelName(LabelDefinition label) { |
550 return '\$${label.labelName}\$${label.target.nestingLevel}'; | 564 return '\$${label.labelName}\$${label.target.nestingLevel}'; |
551 } | 565 } |
552 | 566 |
553 String implicitBreakLabelName(JumpTarget target) { | 567 String implicitBreakLabelName(JumpTarget target) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
604 String name = Elements.reconstructConstructorNameSourceString(method); | 618 String name = Elements.reconstructConstructorNameSourceString(method); |
605 // We include the method suffix on constructor bodies. It has no purpose, | 619 // We include the method suffix on constructor bodies. It has no purpose, |
606 // but this way it produces the same names as previous versions of the | 620 // but this way it produces the same names as previous versions of the |
607 // Namer class did. | 621 // Namer class did. |
608 List<String> suffix = callSuffixForSignature(method.functionSignature); | 622 List<String> suffix = callSuffixForSignature(method.functionSignature); |
609 return '$name\$${suffix.join(r'$')}'; | 623 return '$name\$${suffix.join(r'$')}'; |
610 } | 624 } |
611 | 625 |
612 /// Name for a constructor body. | 626 /// Name for a constructor body. |
613 jsAst.Name constructorBodyName(FunctionElement ctor) { | 627 jsAst.Name constructorBodyName(FunctionElement ctor) { |
614 return _disambiguateInternalMember(ctor, | 628 return _disambiguateInternalMember( |
615 () => _proposeNameForConstructorBody(ctor)); | 629 ctor, () => _proposeNameForConstructorBody(ctor)); |
616 } | 630 } |
617 | 631 |
618 /// Annotated name for [method] encoding arity and named parameters. | 632 /// Annotated name for [method] encoding arity and named parameters. |
619 jsAst.Name instanceMethodName(FunctionElement method) { | 633 jsAst.Name instanceMethodName(FunctionElement method) { |
620 if (method.isGenerativeConstructorBody) { | 634 if (method.isGenerativeConstructorBody) { |
621 return constructorBodyName(method); | 635 return constructorBodyName(method); |
622 } | 636 } |
623 return invocationName(new Selector.fromElement(method)); | 637 return invocationName(new Selector.fromElement(method)); |
624 } | 638 } |
625 | 639 |
626 String _jsNameHelper(Element e) { | 640 String _jsNameHelper(Element e) { |
627 String jsInteropName = backend.nativeData.getJsInteropName(e); | 641 String jsInteropName = backend.nativeData.getJsInteropName(e); |
628 if (jsInteropName != null && jsInteropName.isNotEmpty) | 642 if (jsInteropName != null && jsInteropName.isNotEmpty) return jsInteropName; |
629 return jsInteropName; | |
630 return e.isLibrary ? 'self' : e.name; | 643 return e.isLibrary ? 'self' : e.name; |
631 } | 644 } |
632 | 645 |
633 /// Returns a JavaScript path specifying the context in which | 646 /// Returns a JavaScript path specifying the context in which |
634 /// [element.fixedBackendName] should be evaluated. Only applicable for | 647 /// [element.fixedBackendName] should be evaluated. Only applicable for |
635 /// elements using typed JavaScript interop. | 648 /// elements using typed JavaScript interop. |
636 /// For example: fixedBackendPath for the static method createMap in the | 649 /// For example: fixedBackendPath for the static method createMap in the |
637 /// Map class of the goog.map JavaScript library would have path | 650 /// Map class of the goog.map JavaScript library would have path |
638 /// "goog.maps.Map". | 651 /// "goog.maps.Map". |
639 String fixedBackendPath(Element element) { | 652 String fixedBackendPath(Element element) { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
687 suffixes.add(param.name); | 700 suffixes.add(param.name); |
688 } | 701 } |
689 } | 702 } |
690 return suffixes; | 703 return suffixes; |
691 } | 704 } |
692 | 705 |
693 /// Annotated name for the member being invoked by [selector]. | 706 /// Annotated name for the member being invoked by [selector]. |
694 jsAst.Name invocationName(Selector selector) { | 707 jsAst.Name invocationName(Selector selector) { |
695 switch (selector.kind) { | 708 switch (selector.kind) { |
696 case SelectorKind.GETTER: | 709 case SelectorKind.GETTER: |
697 jsAst.Name disambiguatedName = | 710 jsAst.Name disambiguatedName = _disambiguateMember(selector.memberName); |
698 _disambiguateMember(selector.memberName); | |
699 return deriveGetterName(disambiguatedName); | 711 return deriveGetterName(disambiguatedName); |
700 | 712 |
701 case SelectorKind.SETTER: | 713 case SelectorKind.SETTER: |
702 jsAst.Name disambiguatedName = | 714 jsAst.Name disambiguatedName = _disambiguateMember(selector.memberName); |
703 _disambiguateMember(selector.memberName); | |
704 return deriveSetterName(disambiguatedName); | 715 return deriveSetterName(disambiguatedName); |
705 | 716 |
706 case SelectorKind.OPERATOR: | 717 case SelectorKind.OPERATOR: |
707 case SelectorKind.INDEX: | 718 case SelectorKind.INDEX: |
708 String operatorIdentifier = operatorNameToIdentifier(selector.name); | 719 String operatorIdentifier = operatorNameToIdentifier(selector.name); |
709 jsAst.Name disambiguatedName = | 720 jsAst.Name disambiguatedName = |
710 _disambiguateOperator(operatorIdentifier); | 721 _disambiguateOperator(operatorIdentifier); |
711 return disambiguatedName; // Operators are not annotated. | 722 return disambiguatedName; // Operators are not annotated. |
712 | 723 |
713 case SelectorKind.CALL: | 724 case SelectorKind.CALL: |
714 List<String> suffix = callSuffixForStructure(selector.callStructure); | 725 List<String> suffix = callSuffixForStructure(selector.callStructure); |
715 if (selector.name == Identifiers.call) { | 726 if (selector.name == Identifiers.call) { |
716 // Derive the annotated name for this variant of 'call'. | 727 // Derive the annotated name for this variant of 'call'. |
717 return deriveCallMethodName(suffix); | 728 return deriveCallMethodName(suffix); |
718 } | 729 } |
719 jsAst.Name disambiguatedName = | 730 jsAst.Name disambiguatedName = |
720 _disambiguateMember(selector.memberName, suffix); | 731 _disambiguateMember(selector.memberName, suffix); |
721 return disambiguatedName; // Methods other than call are not annotated. | 732 return disambiguatedName; // Methods other than call are not annotated. |
722 | 733 |
723 default: | 734 default: |
724 reporter.internalError( | 735 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, |
725 CURRENT_ELEMENT_SPANNABLE, | |
726 'Unexpected selector kind: ${selector.kind}'); | 736 'Unexpected selector kind: ${selector.kind}'); |
727 return null; | 737 return null; |
728 } | 738 } |
729 } | 739 } |
730 | 740 |
731 /** | 741 /** |
732 * Returns the internal name used for an invocation mirror of this selector. | 742 * Returns the internal name used for an invocation mirror of this selector. |
733 */ | 743 */ |
734 jsAst.Name invocationMirrorInternalName(Selector selector) | 744 jsAst.Name invocationMirrorInternalName(Selector selector) => |
735 => invocationName(selector); | 745 invocationName(selector); |
736 | 746 |
737 /** | 747 /** |
738 * Returns the disambiguated name for the given field, used for constructing | 748 * Returns the disambiguated name for the given field, used for constructing |
739 * the getter and setter names. | 749 * the getter and setter names. |
740 */ | 750 */ |
741 jsAst.Name fieldAccessorName(FieldElement element) { | 751 jsAst.Name fieldAccessorName(FieldElement element) { |
742 return element.isInstanceMember | 752 return element.isInstanceMember |
743 ? _disambiguateMember(element.memberName) | 753 ? _disambiguateMember(element.memberName) |
744 : _disambiguateGlobal(element); | 754 : _disambiguateGlobal(element); |
745 } | 755 } |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 | 796 |
787 // Some elements, like e.g. instances of BoxFieldElement are special. | 797 // Some elements, like e.g. instances of BoxFieldElement are special. |
788 // They are created with a unique and safe name for the element model. | 798 // They are created with a unique and safe name for the element model. |
789 // While their name is unique, it is not very readable. So we try to | 799 // While their name is unique, it is not very readable. So we try to |
790 // preserve the original, proposed name. | 800 // preserve the original, proposed name. |
791 // However, as boxes are not really instances of classes, the usual naming | 801 // However, as boxes are not really instances of classes, the usual naming |
792 // scheme that tries to avoid name clashes with super classes does not | 802 // scheme that tries to avoid name clashes with super classes does not |
793 // apply. So we can directly grab a name. | 803 // apply. So we can directly grab a name. |
794 Entity asEntity = element; | 804 Entity asEntity = element; |
795 if (asEntity is JSEntity) { | 805 if (asEntity is JSEntity) { |
796 return _disambiguateInternalMember(element, | 806 return _disambiguateInternalMember( |
797 () => asEntity.declaredEntity.name); | 807 element, () => asEntity.declaredEntity.name); |
798 } | 808 } |
799 | 809 |
800 // If the name of the field might clash with another field, | 810 // If the name of the field might clash with another field, |
801 // use a mangled field name to avoid potential clashes. | 811 // use a mangled field name to avoid potential clashes. |
802 // Note that if the class extends a native class, that native class might | 812 // Note that if the class extends a native class, that native class might |
803 // have fields with fixed backend names, so we assume the worst and always | 813 // have fields with fixed backend names, so we assume the worst and always |
804 // mangle the field names of classes extending native classes. | 814 // mangle the field names of classes extending native classes. |
805 // Methods on such classes are stored on the interceptor, not the instance, | 815 // Methods on such classes are stored on the interceptor, not the instance, |
806 // so only fields have the potential to clash with a native property name. | 816 // so only fields have the potential to clash with a native property name. |
807 ClassWorld classWorld = compiler.world; | 817 ClassWorld classWorld = compiler.world; |
(...skipping 10 matching lines...) Expand all Loading... |
818 return _disambiguateMember(element.memberName); | 828 return _disambiguateMember(element.memberName); |
819 } | 829 } |
820 | 830 |
821 bool _isShadowingSuperField(Element element) { | 831 bool _isShadowingSuperField(Element element) { |
822 return element.enclosingClass.hasFieldShadowedBy(element); | 832 return element.enclosingClass.hasFieldShadowedBy(element); |
823 } | 833 } |
824 | 834 |
825 /// True if [class_] is a non-native class that inherits from a native class. | 835 /// True if [class_] is a non-native class that inherits from a native class. |
826 bool _isUserClassExtendingNative(ClassElement class_) { | 836 bool _isUserClassExtendingNative(ClassElement class_) { |
827 return !backend.isNative(class_) && | 837 return !backend.isNative(class_) && |
828 backend.isNativeOrExtendsNative(class_.superclass); | 838 backend.isNativeOrExtendsNative(class_.superclass); |
829 } | 839 } |
830 | 840 |
831 /// Annotated name for the setter of [element]. | 841 /// Annotated name for the setter of [element]. |
832 jsAst.Name setterForElement(MemberElement element) { | 842 jsAst.Name setterForElement(MemberElement element) { |
833 // We dynamically create setters from the field-name. The setter name must | 843 // We dynamically create setters from the field-name. The setter name must |
834 // therefore be derived from the instance field-name. | 844 // therefore be derived from the instance field-name. |
835 jsAst.Name name = _disambiguateMember(element.memberName); | 845 jsAst.Name name = _disambiguateMember(element.memberName); |
836 return deriveSetterName(name); | 846 return deriveSetterName(name); |
837 } | 847 } |
838 | 848 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
894 | 904 |
895 /// Generates a unique key for [library]. | 905 /// Generates a unique key for [library]. |
896 /// | 906 /// |
897 /// Keys are meant to be used in maps and should not be visible in the output. | 907 /// Keys are meant to be used in maps and should not be visible in the output. |
898 String _generateLibraryKey(LibraryElement library) { | 908 String _generateLibraryKey(LibraryElement library) { |
899 return _libraryKeys.putIfAbsent(library, () { | 909 return _libraryKeys.putIfAbsent(library, () { |
900 String keyBase = library.name; | 910 String keyBase = library.name; |
901 int counter = 0; | 911 int counter = 0; |
902 String key = keyBase; | 912 String key = keyBase; |
903 while (_libraryKeys.values.contains(key)) { | 913 while (_libraryKeys.values.contains(key)) { |
904 key ="$keyBase${counter++}"; | 914 key = "$keyBase${counter++}"; |
905 } | 915 } |
906 return key; | 916 return key; |
907 }); | 917 }); |
908 } | 918 } |
909 | 919 |
910 /// Returns the disambiguated name for a top-level or static element. | 920 /// Returns the disambiguated name for a top-level or static element. |
911 /// | 921 /// |
912 /// The resulting name is unique within the global-member namespace. | 922 /// The resulting name is unique within the global-member namespace. |
913 jsAst.Name _disambiguateGlobal(Element element) { | 923 jsAst.Name _disambiguateGlobal(Element element) { |
914 // TODO(asgerf): We can reuse more short names if we disambiguate with | 924 // TODO(asgerf): We can reuse more short names if we disambiguate with |
(...skipping 18 matching lines...) Expand all Loading... |
933 /// | 943 /// |
934 /// [suffixes] denote an extension of [originalName] to distiguish it from | 944 /// [suffixes] denote an extension of [originalName] to distiguish it from |
935 /// other members with that name. These are used to encode the arity and | 945 /// other members with that name. These are used to encode the arity and |
936 /// named parameters to a method. Disambiguating the same [originalName] with | 946 /// named parameters to a method. Disambiguating the same [originalName] with |
937 /// different [suffixes] will yield different disambiguated names. | 947 /// different [suffixes] will yield different disambiguated names. |
938 /// | 948 /// |
939 /// The resulting name, and its associated annotated names, are unique | 949 /// The resulting name, and its associated annotated names, are unique |
940 /// to the ([originalName], [suffixes]) pair within the instance-member | 950 /// to the ([originalName], [suffixes]) pair within the instance-member |
941 /// namespace. | 951 /// namespace. |
942 jsAst.Name _disambiguateMember(Name originalName, | 952 jsAst.Name _disambiguateMember(Name originalName, |
943 [List<String> suffixes = const []]) { | 953 [List<String> suffixes = const []]) { |
944 // Build a string encoding the library name, if the name is private. | 954 // Build a string encoding the library name, if the name is private. |
945 String libraryKey = originalName.isPrivate | 955 String libraryKey = |
946 ? _generateLibraryKey(originalName.library) | 956 originalName.isPrivate ? _generateLibraryKey(originalName.library) : ''; |
947 : ''; | |
948 | 957 |
949 // In the unique key, separate the name parts by '@'. | 958 // In the unique key, separate the name parts by '@'. |
950 // This avoids clashes since the original names cannot contain that symbol. | 959 // This avoids clashes since the original names cannot contain that symbol. |
951 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; | 960 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; |
952 jsAst.Name newName = userInstanceMembers[key]; | 961 jsAst.Name newName = userInstanceMembers[key]; |
953 if (newName == null) { | 962 if (newName == null) { |
954 String proposedName = privateName(originalName); | 963 String proposedName = privateName(originalName); |
955 if (!suffixes.isEmpty) { | 964 if (!suffixes.isEmpty) { |
956 // In the proposed name, separate the name parts by '$', because the | 965 // In the proposed name, separate the name parts by '$', because the |
957 // proposed name must be a valid identifier, but not necessarily unique. | 966 // proposed name must be a valid identifier, but not necessarily unique. |
958 proposedName += r'$' + suffixes.join(r'$'); | 967 proposedName += r'$' + suffixes.join(r'$'); |
959 } | 968 } |
960 newName = getFreshName(instanceScope, proposedName, | 969 newName = getFreshName(instanceScope, proposedName, |
961 sanitizeForAnnotations: true); | 970 sanitizeForAnnotations: true); |
962 userInstanceMembers[key] = newName; | 971 userInstanceMembers[key] = newName; |
963 } | 972 } |
964 return _newReference(newName); | 973 return _newReference(newName); |
965 } | 974 } |
966 | 975 |
967 /// Returns the disambiguated name for the instance member identified by | 976 /// Returns the disambiguated name for the instance member identified by |
968 /// [key]. | 977 /// [key]. |
969 /// | 978 /// |
970 /// When a name for an element is requested by key, it may not be requested | 979 /// When a name for an element is requested by key, it may not be requested |
971 /// by element at the same time, as two different names would be returned. | 980 /// by element at the same time, as two different names would be returned. |
972 /// | 981 /// |
973 /// If key has not yet been registered, [proposeName] is used to generate | 982 /// If key has not yet been registered, [proposeName] is used to generate |
974 /// a name proposal for the given key. | 983 /// a name proposal for the given key. |
975 /// | 984 /// |
976 /// [key] must not clash with valid instance names. This is typically | 985 /// [key] must not clash with valid instance names. This is typically |
977 /// achieved by using at least one character in [key] that is not valid in | 986 /// achieved by using at least one character in [key] that is not valid in |
978 /// identifiers, for example the @ symbol. | 987 /// identifiers, for example the @ symbol. |
979 jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) { | 988 jsAst.Name _disambiguateMemberByKey(String key, String proposeName()) { |
980 jsAst.Name newName = userInstanceMembers[key]; | 989 jsAst.Name newName = userInstanceMembers[key]; |
981 if (newName == null) { | 990 if (newName == null) { |
982 String name = proposeName(); | 991 String name = proposeName(); |
983 newName = getFreshName(instanceScope, name, | 992 newName = getFreshName(instanceScope, name, sanitizeForAnnotations: true); |
984 sanitizeForAnnotations: true); | |
985 userInstanceMembers[key] = newName; | 993 userInstanceMembers[key] = newName; |
986 } | 994 } |
987 return _newReference(newName); | 995 return _newReference(newName); |
988 } | 996 } |
989 | 997 |
990 /// Forces the public instance member with [originalName] to have the given | 998 /// Forces the public instance member with [originalName] to have the given |
991 /// [disambiguatedName]. | 999 /// [disambiguatedName]. |
992 /// | 1000 /// |
993 /// The [originalName] must not have been disambiguated before, and the | 1001 /// The [originalName] must not have been disambiguated before, and the |
994 /// [disambiguatedName] must not have been used. | 1002 /// [disambiguatedName] must not have been used. |
995 /// | 1003 /// |
996 /// Using [_disambiguateMember] with the given [originalName] and no suffixes | 1004 /// Using [_disambiguateMember] with the given [originalName] and no suffixes |
997 /// will subsequently return [disambiguatedName]. | 1005 /// will subsequently return [disambiguatedName]. |
998 void reservePublicMemberName(String originalName, | 1006 void reservePublicMemberName(String originalName, String disambiguatedName) { |
999 String disambiguatedName) { | |
1000 // Build a key that corresponds to the one built in disambiguateMember. | 1007 // Build a key that corresponds to the one built in disambiguateMember. |
1001 String libraryPrefix = ''; // Public names have an empty library prefix. | 1008 String libraryPrefix = ''; // Public names have an empty library prefix. |
1002 String suffix = ''; // We don't need any suffixes. | 1009 String suffix = ''; // We don't need any suffixes. |
1003 String key = '$libraryPrefix@$originalName@$suffix'; | 1010 String key = '$libraryPrefix@$originalName@$suffix'; |
1004 assert(!userInstanceMembers.containsKey(key)); | 1011 assert(!userInstanceMembers.containsKey(key)); |
1005 assert(!instanceScope.isUsed(disambiguatedName)); | 1012 assert(!instanceScope.isUsed(disambiguatedName)); |
1006 userInstanceMembers[key] = new StringBackedName(disambiguatedName); | 1013 userInstanceMembers[key] = new StringBackedName(disambiguatedName); |
1007 instanceScope.registerUse(disambiguatedName); | 1014 instanceScope.registerUse(disambiguatedName); |
1008 } | 1015 } |
1009 | 1016 |
1010 /// Disambiguated name unique to [element]. | 1017 /// Disambiguated name unique to [element]. |
1011 /// | 1018 /// |
1012 /// This is used as the property name for fields, type variables, | 1019 /// This is used as the property name for fields, type variables, |
1013 /// constructor bodies, and super-accessors. | 1020 /// constructor bodies, and super-accessors. |
1014 /// | 1021 /// |
1015 /// The resulting name is unique within the instance-member namespace. | 1022 /// The resulting name is unique within the instance-member namespace. |
1016 jsAst.Name _disambiguateInternalMember(Element element, | 1023 jsAst.Name _disambiguateInternalMember( |
1017 String proposeName()) { | 1024 Element element, String proposeName()) { |
1018 jsAst.Name newName = internalInstanceMembers[element]; | 1025 jsAst.Name newName = internalInstanceMembers[element]; |
1019 if (newName == null) { | 1026 if (newName == null) { |
1020 String name = proposeName(); | 1027 String name = proposeName(); |
1021 | 1028 |
1022 Entity asEntity = element; | 1029 Entity asEntity = element; |
1023 if (asEntity is PrivatelyNamedJSEntity) { | 1030 if (asEntity is PrivatelyNamedJSEntity) { |
1024 NamingScope scope = _getPrivateScopeFor(asEntity); | 1031 NamingScope scope = _getPrivateScopeFor(asEntity); |
1025 newName = getFreshName(scope, name, | 1032 newName = getFreshName(scope, name, |
1026 sanitizeForAnnotations: true, | 1033 sanitizeForAnnotations: true, sanitizeForNatives: false); |
1027 sanitizeForNatives: false); | |
1028 internalInstanceMembers[element] = newName; | 1034 internalInstanceMembers[element] = newName; |
1029 } else { | 1035 } else { |
1030 bool mayClashNative = | 1036 bool mayClashNative = |
1031 _isUserClassExtendingNative(element.enclosingClass); | 1037 _isUserClassExtendingNative(element.enclosingClass); |
1032 newName = getFreshName(instanceScope, name, | 1038 newName = getFreshName(instanceScope, name, |
1033 sanitizeForAnnotations: true, | 1039 sanitizeForAnnotations: true, sanitizeForNatives: mayClashNative); |
1034 sanitizeForNatives: mayClashNative); | |
1035 internalInstanceMembers[element] = newName; | 1040 internalInstanceMembers[element] = newName; |
1036 } | 1041 } |
1037 } | 1042 } |
1038 return _newReference(newName); | 1043 return _newReference(newName); |
1039 } | 1044 } |
1040 | 1045 |
1041 /// Disambiguated name for the given operator. | 1046 /// Disambiguated name for the given operator. |
1042 /// | 1047 /// |
1043 /// [operatorIdentifier] must be the operator's identifier, e.g. | 1048 /// [operatorIdentifier] must be the operator's identifier, e.g. |
1044 /// `$add` and not `+`. | 1049 /// `$add` and not `+`. |
1045 /// | 1050 /// |
1046 /// The resulting name is unique within the instance-member namespace. | 1051 /// The resulting name is unique within the instance-member namespace. |
1047 jsAst.Name _disambiguateOperator(String operatorIdentifier) { | 1052 jsAst.Name _disambiguateOperator(String operatorIdentifier) { |
1048 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; | 1053 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; |
1049 if (newName == null) { | 1054 if (newName == null) { |
1050 newName = getFreshName(instanceScope, operatorIdentifier); | 1055 newName = getFreshName(instanceScope, operatorIdentifier); |
1051 userInstanceOperators[operatorIdentifier] = newName; | 1056 userInstanceOperators[operatorIdentifier] = newName; |
1052 } | 1057 } |
1053 return _newReference(newName); | 1058 return _newReference(newName); |
1054 } | 1059 } |
1055 | 1060 |
1056 String _generateFreshStringForName(String proposedName, | 1061 String _generateFreshStringForName(String proposedName, NamingScope scope, |
1057 NamingScope scope, | 1062 {bool sanitizeForAnnotations: false, bool sanitizeForNatives: false}) { |
1058 {bool sanitizeForAnnotations: false, | |
1059 bool sanitizeForNatives: false}) { | |
1060 if (sanitizeForAnnotations) { | 1063 if (sanitizeForAnnotations) { |
1061 proposedName = _sanitizeForAnnotations(proposedName); | 1064 proposedName = _sanitizeForAnnotations(proposedName); |
1062 } | 1065 } |
1063 if (sanitizeForNatives) { | 1066 if (sanitizeForNatives) { |
1064 proposedName = _sanitizeForNatives(proposedName); | 1067 proposedName = _sanitizeForNatives(proposedName); |
1065 } | 1068 } |
1066 proposedName = _sanitizeForKeywords(proposedName); | 1069 proposedName = _sanitizeForKeywords(proposedName); |
1067 String candidate; | 1070 String candidate; |
1068 if (scope.isUnused(proposedName)) { | 1071 if (scope.isUnused(proposedName)) { |
1069 candidate = proposedName; | 1072 candidate = proposedName; |
(...skipping 15 matching lines...) Expand all Loading... |
1085 /// [proposedName] must be a valid JavaScript identifier. | 1088 /// [proposedName] must be a valid JavaScript identifier. |
1086 /// | 1089 /// |
1087 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not | 1090 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not |
1088 /// to have the form of an annotated name. | 1091 /// to have the form of an annotated name. |
1089 /// | 1092 /// |
1090 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to | 1093 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to |
1091 /// clash with a property name on a native object. | 1094 /// clash with a property name on a native object. |
1092 /// | 1095 /// |
1093 /// Note that [MinifyNamer] overrides this method with one that produces | 1096 /// Note that [MinifyNamer] overrides this method with one that produces |
1094 /// minified names. | 1097 /// minified names. |
1095 jsAst.Name getFreshName(NamingScope scope, | 1098 jsAst.Name getFreshName(NamingScope scope, String proposedName, |
1096 String proposedName, | 1099 {bool sanitizeForAnnotations: false, bool sanitizeForNatives: false}) { |
1097 {bool sanitizeForAnnotations: false, | 1100 String candidate = _generateFreshStringForName(proposedName, scope, |
1098 bool sanitizeForNatives: false}) { | 1101 sanitizeForAnnotations: sanitizeForAnnotations, |
1099 String candidate = | 1102 sanitizeForNatives: sanitizeForNatives); |
1100 _generateFreshStringForName(proposedName, | |
1101 scope, | |
1102 sanitizeForAnnotations: | |
1103 sanitizeForAnnotations, | |
1104 sanitizeForNatives: sanitizeForNatives); | |
1105 return new StringBackedName(candidate); | 1103 return new StringBackedName(candidate); |
1106 } | 1104 } |
1107 | 1105 |
1108 /// Returns a variant of [name] that cannot clash with the annotated | 1106 /// Returns a variant of [name] that cannot clash with the annotated |
1109 /// version of another name, that is, the resulting name can never be returned | 1107 /// version of another name, that is, the resulting name can never be returned |
1110 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], | 1108 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], |
1111 /// [operatorIs], or [substitutionName]. | 1109 /// [operatorIs], or [substitutionName]. |
1112 /// | 1110 /// |
1113 /// For example, a name `get$x` would be converted to `$get$x` to ensure it | 1111 /// For example, a name `get$x` would be converted to `$get$x` to ensure it |
1114 /// cannot clash with the getter for `x`. | 1112 /// cannot clash with the getter for `x`. |
(...skipping 30 matching lines...) Expand all Loading... |
1145 | 1143 |
1146 /** | 1144 /** |
1147 * Returns a proposed name for the given top-level or static element. | 1145 * Returns a proposed name for the given top-level or static element. |
1148 * The returned id is guaranteed to be a valid JS-id. | 1146 * The returned id is guaranteed to be a valid JS-id. |
1149 */ | 1147 */ |
1150 String _proposeNameForGlobal(Element element) { | 1148 String _proposeNameForGlobal(Element element) { |
1151 assert(!element.isInstanceMember); | 1149 assert(!element.isInstanceMember); |
1152 String name; | 1150 String name; |
1153 if (element.isGenerativeConstructor) { | 1151 if (element.isGenerativeConstructor) { |
1154 name = "${element.enclosingClass.name}\$" | 1152 name = "${element.enclosingClass.name}\$" |
1155 "${element.name}"; | 1153 "${element.name}"; |
1156 } else if (element.isFactoryConstructor) { | 1154 } else if (element.isFactoryConstructor) { |
1157 // TODO(johnniwinther): Change factory name encoding as to not include | 1155 // TODO(johnniwinther): Change factory name encoding as to not include |
1158 // the class-name twice. | 1156 // the class-name twice. |
1159 String className = element.enclosingClass.name; | 1157 String className = element.enclosingClass.name; |
1160 name = '${className}_${Elements.reconstructConstructorName(element)}'; | 1158 name = '${className}_${Elements.reconstructConstructorName(element)}'; |
1161 } else if (Elements.isStaticOrTopLevel(element)) { | 1159 } else if (Elements.isStaticOrTopLevel(element)) { |
1162 if (element.isClassMember) { | 1160 if (element.isClassMember) { |
1163 ClassElement enclosingClass = element.enclosingClass; | 1161 ClassElement enclosingClass = element.enclosingClass; |
1164 name = "${enclosingClass.name}_" | 1162 name = "${enclosingClass.name}_" |
1165 "${element.name}"; | 1163 "${element.name}"; |
1166 } else { | 1164 } else { |
1167 name = element.name.replaceAll('+', '_'); | 1165 name = element.name.replaceAll('+', '_'); |
1168 } | 1166 } |
1169 } else if (element.isLibrary) { | 1167 } else if (element.isLibrary) { |
1170 LibraryElement library = element; | 1168 LibraryElement library = element; |
1171 name = libraryLongNames[library]; | 1169 name = libraryLongNames[library]; |
1172 if (name != null) return name; | 1170 if (name != null) return name; |
1173 name = library.libraryOrScriptName; | 1171 name = library.libraryOrScriptName; |
1174 if (name.contains('.')) { | 1172 if (name.contains('.')) { |
1175 // For libraries that have a library tag, we use the last part | 1173 // For libraries that have a library tag, we use the last part |
1176 // of the fully qualified name as their base name. For all other | 1174 // of the fully qualified name as their base name. For all other |
1177 // libraries, we use the first part of their filename. | 1175 // libraries, we use the first part of their filename. |
1178 name = library.hasLibraryName | 1176 name = library.hasLibraryName |
1179 ? name.substring(name.lastIndexOf('.') + 1) | 1177 ? name.substring(name.lastIndexOf('.') + 1) |
1180 : name.substring(0, name.indexOf('.')); | 1178 : name.substring(0, name.indexOf('.')); |
1181 } | 1179 } |
1182 // The filename based name can contain all kinds of nasty characters. Make | 1180 // The filename based name can contain all kinds of nasty characters. Make |
1183 // sure it is an identifier. | 1181 // sure it is an identifier. |
1184 if (!IDENTIFIER.hasMatch(name)) { | 1182 if (!IDENTIFIER.hasMatch(name)) { |
1185 name = name.replaceAllMapped(NON_IDENTIFIER_CHAR, | 1183 name = name.replaceAllMapped(NON_IDENTIFIER_CHAR, |
1186 (match) => match[0].codeUnitAt(0).toRadixString(16)); | 1184 (match) => match[0].codeUnitAt(0).toRadixString(16)); |
1187 if (!IDENTIFIER.hasMatch(name)) { // e.g. starts with digit. | 1185 if (!IDENTIFIER.hasMatch(name)) { |
| 1186 // e.g. starts with digit. |
1188 name = 'lib_$name'; | 1187 name = 'lib_$name'; |
1189 } | 1188 } |
1190 } | 1189 } |
1191 // Names constructed based on a libary name will be further disambiguated. | 1190 // Names constructed based on a libary name will be further disambiguated. |
1192 // However, as names from the same libary should have the same libary | 1191 // However, as names from the same libary should have the same libary |
1193 // name part, we disambiguate the library name here. | 1192 // name part, we disambiguate the library name here. |
1194 String disambiguated = name; | 1193 String disambiguated = name; |
1195 for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) { | 1194 for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) { |
1196 disambiguated = "$name$c"; | 1195 disambiguated = "$name$c"; |
1197 } | 1196 } |
1198 libraryLongNames[library] = disambiguated; | 1197 libraryLongNames[library] = disambiguated; |
1199 name = disambiguated; | 1198 name = disambiguated; |
1200 } else { | 1199 } else { |
1201 name = element.name; | 1200 name = element.name; |
1202 } | 1201 } |
1203 return name; | 1202 return name; |
1204 } | 1203 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1241 // its element, so we treat this as a user-space global instead of an | 1240 // its element, so we treat this as a user-space global instead of an |
1242 // internal global. | 1241 // internal global. |
1243 return _disambiguateGlobal(getInterceptor); | 1242 return _disambiguateGlobal(getInterceptor); |
1244 } | 1243 } |
1245 String suffix = suffixForGetInterceptor(classes); | 1244 String suffix = suffixForGetInterceptor(classes); |
1246 return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix"); | 1245 return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix"); |
1247 } | 1246 } |
1248 | 1247 |
1249 /// Property name used for the one-shot interceptor method for the given | 1248 /// Property name used for the one-shot interceptor method for the given |
1250 /// [selector] and return-type specialization. | 1249 /// [selector] and return-type specialization. |
1251 jsAst.Name nameForGetOneShotInterceptor(Selector selector, | 1250 jsAst.Name nameForGetOneShotInterceptor( |
1252 Iterable<ClassElement> classes) { | 1251 Selector selector, Iterable<ClassElement> classes) { |
1253 // The one-shot name is a global name derived from the invocation name. To | 1252 // The one-shot name is a global name derived from the invocation name. To |
1254 // avoid instability we would like the names to be unique and not clash with | 1253 // avoid instability we would like the names to be unique and not clash with |
1255 // other global names. | 1254 // other global names. |
1256 jsAst.Name root = invocationName(selector); | 1255 jsAst.Name root = invocationName(selector); |
1257 | 1256 |
1258 if (classes.contains(helpers.jsInterceptorClass)) { | 1257 if (classes.contains(helpers.jsInterceptorClass)) { |
1259 // If the base Interceptor class is in the set of intercepted classes, | 1258 // If the base Interceptor class is in the set of intercepted classes, |
1260 // this is the most general specialization which uses the generic | 1259 // this is the most general specialization which uses the generic |
1261 // getInterceptor method. | 1260 // getInterceptor method. |
1262 // TODO(sra): Find a way to get the simple name when Object is not in the | 1261 // TODO(sra): Find a way to get the simple name when Object is not in the |
1263 // set of classes for most general variant, e.g. "$lt$n" could be "$lt". | 1262 // set of classes for most general variant, e.g. "$lt$n" could be "$lt". |
1264 return new CompoundName([root, _literalDollar]); | 1263 return new CompoundName([root, _literalDollar]); |
1265 } else { | 1264 } else { |
1266 String suffix = suffixForGetInterceptor(classes); | 1265 String suffix = suffixForGetInterceptor(classes); |
1267 return new CompoundName([root, _literalDollar, | 1266 return new CompoundName( |
1268 new StringBackedName(suffix)]); | 1267 [root, _literalDollar, new StringBackedName(suffix)]); |
1269 } | 1268 } |
1270 } | 1269 } |
1271 | 1270 |
1272 /// Returns the runtime name for [element]. | 1271 /// Returns the runtime name for [element]. |
1273 /// | 1272 /// |
1274 /// This name is used as the basis for deriving `is` and `as` property names | 1273 /// This name is used as the basis for deriving `is` and `as` property names |
1275 /// for the given type. | 1274 /// for the given type. |
1276 /// | 1275 /// |
1277 /// The result is not always safe as a property name unless prefixing | 1276 /// The result is not always safe as a property name unless prefixing |
1278 /// [operatorIsPrefix] or [operatorAsPrefix]. If this is a function type, | 1277 /// [operatorIsPrefix] or [operatorAsPrefix]. If this is a function type, |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1347 /// [reservedGlobalObjectNames]. | 1346 /// [reservedGlobalObjectNames]. |
1348 bool _isPropertyOfStaticStateHolder(Element element) { | 1347 bool _isPropertyOfStaticStateHolder(Element element) { |
1349 // TODO(ahe): Make sure this method's documentation is always true and | 1348 // TODO(ahe): Make sure this method's documentation is always true and |
1350 // remove the word "intend". | 1349 // remove the word "intend". |
1351 return | 1350 return |
1352 // TODO(ahe): Re-write these tests to be positive (so it only returns | 1351 // TODO(ahe): Re-write these tests to be positive (so it only returns |
1353 // true for static/top-level mutable fields). Right now, a number of | 1352 // true for static/top-level mutable fields). Right now, a number of |
1354 // other elements, such as bound closures also live in | 1353 // other elements, such as bound closures also live in |
1355 // [staticStateHolder]. | 1354 // [staticStateHolder]. |
1356 !element.isAccessor && | 1355 !element.isAccessor && |
1357 !element.isClass && | 1356 !element.isClass && |
1358 !element.isTypedef && | 1357 !element.isTypedef && |
1359 !element.isConstructor && | 1358 !element.isConstructor && |
1360 !element.isFunction && | 1359 !element.isFunction && |
1361 !element.isLibrary; | 1360 !element.isLibrary; |
1362 } | 1361 } |
1363 | 1362 |
1364 /// Returns [staticStateHolder] or one of [reservedGlobalObjectNames]. | 1363 /// Returns [staticStateHolder] or one of [reservedGlobalObjectNames]. |
1365 String globalObjectFor(Element element) { | 1364 String globalObjectFor(Element element) { |
1366 if (_isPropertyOfStaticStateHolder(element)) return staticStateHolder; | 1365 if (_isPropertyOfStaticStateHolder(element)) return staticStateHolder; |
1367 LibraryElement library = element.library; | 1366 LibraryElement library = element.library; |
1368 if (library == helpers.interceptorsLibrary) return 'J'; | 1367 if (library == helpers.interceptorsLibrary) return 'J'; |
1369 if (library.isInternalLibrary) return 'H'; | 1368 if (library.isInternalLibrary) return 'H'; |
1370 if (library.isPlatformLibrary) { | 1369 if (library.isPlatformLibrary) { |
1371 if ('${library.canonicalUri}' == 'dart:html') return 'W'; | 1370 if ('${library.canonicalUri}' == 'dart:html') return 'W'; |
(...skipping 10 matching lines...) Expand all Loading... |
1382 | 1381 |
1383 jsAst.Name lazyInitializerName(Element element) { | 1382 jsAst.Name lazyInitializerName(Element element) { |
1384 assert(Elements.isStaticOrTopLevelField(element)); | 1383 assert(Elements.isStaticOrTopLevelField(element)); |
1385 jsAst.Name name = _disambiguateGlobal(element); | 1384 jsAst.Name name = _disambiguateGlobal(element); |
1386 // These are not real dart getters, so do not use GetterName; | 1385 // These are not real dart getters, so do not use GetterName; |
1387 return deriveLazyInitializerName(name); | 1386 return deriveLazyInitializerName(name); |
1388 } | 1387 } |
1389 | 1388 |
1390 jsAst.Name staticClosureName(Element element) { | 1389 jsAst.Name staticClosureName(Element element) { |
1391 assert(Elements.isStaticOrTopLevelFunction(element)); | 1390 assert(Elements.isStaticOrTopLevelFunction(element)); |
1392 String enclosing = element.enclosingClass == null | 1391 String enclosing = |
1393 ? "" : element.enclosingClass.name; | 1392 element.enclosingClass == null ? "" : element.enclosingClass.name; |
1394 String library = _proposeNameForGlobal(element.library); | 1393 String library = _proposeNameForGlobal(element.library); |
1395 return _disambiguateInternalGlobal( | 1394 return _disambiguateInternalGlobal( |
1396 "${library}_${enclosing}_${element.name}\$closure"); | 1395 "${library}_${enclosing}_${element.name}\$closure"); |
1397 } | 1396 } |
1398 | 1397 |
1399 // This name is used as part of the name of a TypeConstant | 1398 // This name is used as part of the name of a TypeConstant |
1400 String uniqueNameForTypeConstantElement(Element element) { | 1399 String uniqueNameForTypeConstantElement(Element element) { |
1401 // TODO(sra): If we replace the period with an identifier character, | 1400 // TODO(sra): If we replace the period with an identifier character, |
1402 // TypeConstants will have better names in unminified code. | 1401 // TypeConstants will have better names in unminified code. |
1403 String library = _proposeNameForGlobal(element.library); | 1402 String library = _proposeNameForGlobal(element.library); |
(...skipping 29 matching lines...) Expand all Loading... |
1433 jsAst.Name getFunctionTypeName(FunctionType functionType) { | 1432 jsAst.Name getFunctionTypeName(FunctionType functionType) { |
1434 return functionTypeNameMap.putIfAbsent(functionType, () { | 1433 return functionTypeNameMap.putIfAbsent(functionType, () { |
1435 String proposedName = functionTypeNamer.computeName(functionType); | 1434 String proposedName = functionTypeNamer.computeName(functionType); |
1436 return getFreshName(instanceScope, proposedName); | 1435 return getFreshName(instanceScope, proposedName); |
1437 }); | 1436 }); |
1438 } | 1437 } |
1439 | 1438 |
1440 jsAst.Name operatorIsType(DartType type) { | 1439 jsAst.Name operatorIsType(DartType type) { |
1441 if (type.isFunctionType) { | 1440 if (type.isFunctionType) { |
1442 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. | 1441 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. |
1443 return new CompoundName([new StringBackedName(operatorIsPrefix), | 1442 return new CompoundName([ |
1444 _literalUnderscore, | 1443 new StringBackedName(operatorIsPrefix), |
1445 getFunctionTypeName(type)]); | 1444 _literalUnderscore, |
| 1445 getFunctionTypeName(type) |
| 1446 ]); |
1446 } | 1447 } |
1447 return operatorIs(type.element); | 1448 return operatorIs(type.element); |
1448 } | 1449 } |
1449 | 1450 |
1450 jsAst.Name operatorIs(ClassElement element) { | 1451 jsAst.Name operatorIs(ClassElement element) { |
1451 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. | 1452 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. |
1452 return new CompoundName([new StringBackedName(operatorIsPrefix), | 1453 return new CompoundName( |
1453 runtimeTypeName(element)]); | 1454 [new StringBackedName(operatorIsPrefix), runtimeTypeName(element)]); |
1454 } | 1455 } |
1455 | 1456 |
1456 /// Returns a name that does not clash with reserved JS keywords. | 1457 /// Returns a name that does not clash with reserved JS keywords. |
1457 String _sanitizeForKeywords(String name) { | 1458 String _sanitizeForKeywords(String name) { |
1458 if (jsReserved.contains(name)) { | 1459 if (jsReserved.contains(name)) { |
1459 name = '\$$name'; | 1460 name = '\$$name'; |
1460 } | 1461 } |
1461 assert(!jsReserved.contains(name)); | 1462 assert(!jsReserved.contains(name)); |
1462 return name; | 1463 return name; |
1463 } | 1464 } |
1464 | 1465 |
1465 jsAst.Name substitutionName(Element element) { | 1466 jsAst.Name substitutionName(Element element) { |
1466 return new CompoundName([new StringBackedName(operatorAsPrefix), | 1467 return new CompoundName( |
1467 runtimeTypeName(element)]); | 1468 [new StringBackedName(operatorAsPrefix), runtimeTypeName(element)]); |
1468 } | 1469 } |
1469 | 1470 |
1470 /// Translates a [String] into the corresponding [Name] data structure as | 1471 /// Translates a [String] into the corresponding [Name] data structure as |
1471 /// used by the namer. | 1472 /// used by the namer. |
1472 /// | 1473 /// |
1473 /// If [name] is a setter or getter name, the corresponding [GetterName] or | 1474 /// If [name] is a setter or getter name, the corresponding [GetterName] or |
1474 /// [SetterName] data structure is used. | 1475 /// [SetterName] data structure is used. |
1475 jsAst.Name asName(String name) { | 1476 jsAst.Name asName(String name) { |
1476 if (name.startsWith(getterPrefix) && name.length > getterPrefix.length) { | 1477 if (name.startsWith(getterPrefix) && name.length > getterPrefix.length) { |
1477 return new GetterName(_literalGetterPrefix, | 1478 return new GetterName(_literalGetterPrefix, |
1478 new StringBackedName( | 1479 new StringBackedName(name.substring(getterPrefix.length))); |
1479 name.substring(getterPrefix.length))); | |
1480 } | 1480 } |
1481 if (name.startsWith(setterPrefix) && name.length > setterPrefix.length) { | 1481 if (name.startsWith(setterPrefix) && name.length > setterPrefix.length) { |
1482 return new GetterName(_literalSetterPrefix, | 1482 return new GetterName(_literalSetterPrefix, |
1483 new StringBackedName( | 1483 new StringBackedName(name.substring(setterPrefix.length))); |
1484 name.substring(setterPrefix.length))); | |
1485 } | 1484 } |
1486 | 1485 |
1487 return new StringBackedName(name); | 1486 return new StringBackedName(name); |
1488 } | 1487 } |
1489 | 1488 |
1490 /// Returns a variable name that cannot clash with a keyword, a global | 1489 /// Returns a variable name that cannot clash with a keyword, a global |
1491 /// variable, or any name starting with a single '$'. | 1490 /// variable, or any name starting with a single '$'. |
1492 /// | 1491 /// |
1493 /// Furthermore, this function is injective, that is, it never returns the | 1492 /// Furthermore, this function is injective, that is, it never returns the |
1494 /// same name for two different inputs. | 1493 /// same name for two different inputs. |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1582 * | 1581 * |
1583 * List_imX // A List, with hash tag. | 1582 * List_imX // A List, with hash tag. |
1584 * C_Sentinel // const Sentinel(), "C_" added to avoid clash | 1583 * C_Sentinel // const Sentinel(), "C_" added to avoid clash |
1585 * // with class name. | 1584 * // with class name. |
1586 * JSInt_methods // an interceptor. | 1585 * JSInt_methods // an interceptor. |
1587 * Duration_16000 // const Duration(milliseconds: 16) | 1586 * Duration_16000 // const Duration(milliseconds: 16) |
1588 * EventKeyProvider_keyup // const EventKeyProvider('keyup') | 1587 * EventKeyProvider_keyup // const EventKeyProvider('keyup') |
1589 * | 1588 * |
1590 */ | 1589 */ |
1591 class ConstantNamingVisitor implements ConstantValueVisitor { | 1590 class ConstantNamingVisitor implements ConstantValueVisitor { |
1592 | |
1593 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); | 1591 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); |
1594 static const MAX_FRAGMENTS = 5; | 1592 static const MAX_FRAGMENTS = 5; |
1595 static const MAX_EXTRA_LENGTH = 30; | 1593 static const MAX_EXTRA_LENGTH = 30; |
1596 static const DEFAULT_TAG_LENGTH = 3; | 1594 static const DEFAULT_TAG_LENGTH = 3; |
1597 | 1595 |
1598 final Compiler compiler; | 1596 final Compiler compiler; |
1599 final ConstantCanonicalHasher hasher; | 1597 final ConstantCanonicalHasher hasher; |
1600 | 1598 |
1601 String root = null; // First word, usually a type name. | 1599 String root = null; // First word, usually a type name. |
1602 bool failed = false; // Failed to generate something pretty. | 1600 bool failed = false; // Failed to generate something pretty. |
1603 List<String> fragments = <String>[]; | 1601 List<String> fragments = <String>[]; |
1604 int length = 0; | 1602 int length = 0; |
1605 | 1603 |
1606 ConstantNamingVisitor(this.compiler, this.hasher); | 1604 ConstantNamingVisitor(this.compiler, this.hasher); |
1607 | 1605 |
1608 DiagnosticReporter get reporter => compiler.reporter; | 1606 DiagnosticReporter get reporter => compiler.reporter; |
1609 | 1607 |
1610 String getName(ConstantValue constant) { | 1608 String getName(ConstantValue constant) { |
1611 _visit(constant); | 1609 _visit(constant); |
1612 if (root == null) return 'CONSTANT'; | 1610 if (root == null) return 'CONSTANT'; |
1613 if (failed) return '${root}_${getHashTag(constant, DEFAULT_TAG_LENGTH)}'; | 1611 if (failed) return '${root}_${getHashTag(constant, DEFAULT_TAG_LENGTH)}'; |
1614 if (fragments.length == 1) return 'C_${root}'; | 1612 if (fragments.length == 1) return 'C_${root}'; |
1615 return fragments.join('_'); | 1613 return fragments.join('_'); |
1616 } | 1614 } |
1617 | 1615 |
1618 String getHashTag(ConstantValue constant, int width) => | 1616 String getHashTag(ConstantValue constant, int width) => |
1619 hashWord(hasher.getHash(constant), width); | 1617 hashWord(hasher.getHash(constant), width); |
1620 | 1618 |
1621 String hashWord(int hash, int length) { | 1619 String hashWord(int hash, int length) { |
1622 hash &= 0x1fffffff; | 1620 hash &= 0x1fffffff; |
1623 StringBuffer sb = new StringBuffer(); | 1621 StringBuffer sb = new StringBuffer(); |
1624 for (int i = 0; i < length; i++) { | 1622 for (int i = 0; i < length; i++) { |
1625 int digit = hash % 62; | 1623 int digit = hash % 62; |
1626 sb.write('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' | 1624 sb.write('0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'[ |
1627 [digit]); | 1625 digit]); |
1628 hash ~/= 62; | 1626 hash ~/= 62; |
1629 if (hash == 0) break; | 1627 if (hash == 0) break; |
1630 } | 1628 } |
1631 return sb.toString(); | 1629 return sb.toString(); |
1632 } | 1630 } |
1633 | 1631 |
1634 void addRoot(String fragment) { | 1632 void addRoot(String fragment) { |
1635 if (root == null && fragments.isEmpty) { | 1633 if (root == null && fragments.isEmpty) { |
1636 root = fragment; | 1634 root = fragment; |
1637 } | 1635 } |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1735 } | 1733 } |
1736 } | 1734 } |
1737 | 1735 |
1738 @override | 1736 @override |
1739 void visitType(TypeConstantValue constant, [_]) { | 1737 void visitType(TypeConstantValue constant, [_]) { |
1740 // Generates something like 'Type_String_k8F', using the simple name of the | 1738 // Generates something like 'Type_String_k8F', using the simple name of the |
1741 // type and a hash to disambiguate the same name in different libraries. | 1739 // type and a hash to disambiguate the same name in different libraries. |
1742 addRoot('Type'); | 1740 addRoot('Type'); |
1743 DartType type = constant.representedType; | 1741 DartType type = constant.representedType; |
1744 String name = type.element?.name; | 1742 String name = type.element?.name; |
1745 if (name == null) { // e.g. DartType 'dynamic' has no element. | 1743 if (name == null) { |
| 1744 // e.g. DartType 'dynamic' has no element. |
1746 JavaScriptBackend backend = compiler.backend; | 1745 JavaScriptBackend backend = compiler.backend; |
1747 name = backend.rtiEncoder.getTypeRepresentationForTypeConstant(type); | 1746 name = backend.rtiEncoder.getTypeRepresentationForTypeConstant(type); |
1748 } | 1747 } |
1749 addIdentifier(name); | 1748 addIdentifier(name); |
1750 add(getHashTag(constant, 3)); | 1749 add(getHashTag(constant, 3)); |
1751 } | 1750 } |
1752 | 1751 |
1753 @override | 1752 @override |
1754 void visitInterceptor(InterceptorConstantValue constant, [_]) { | 1753 void visitInterceptor(InterceptorConstantValue constant, [_]) { |
1755 addRoot(constant.dispatchedType.element.name); | 1754 addRoot(constant.dispatchedType.element.name); |
1756 add('methods'); | 1755 add('methods'); |
1757 } | 1756 } |
1758 | 1757 |
1759 @override | 1758 @override |
1760 void visitSynthetic(SyntheticConstantValue constant, [_]) { | 1759 void visitSynthetic(SyntheticConstantValue constant, [_]) { |
1761 switch (constant.kind) { | 1760 switch (constant.kind) { |
1762 case SyntheticConstantKind.DUMMY_INTERCEPTOR: | 1761 case SyntheticConstantKind.DUMMY_INTERCEPTOR: |
1763 add('dummy_receiver'); | 1762 add('dummy_receiver'); |
1764 break; | 1763 break; |
1765 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: | 1764 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: |
1766 // Omit. These are opaque deferred indexes with nothing helpful to add. | 1765 // Omit. These are opaque deferred indexes with nothing helpful to add. |
1767 break; | 1766 break; |
1768 case SyntheticConstantKind.NAME: | 1767 case SyntheticConstantKind.NAME: |
1769 add('name'); | 1768 add('name'); |
1770 break; | 1769 break; |
1771 default: | 1770 default: |
1772 reporter.internalError(CURRENT_ELEMENT_SPANNABLE, | 1771 reporter.internalError( |
1773 "Unexpected SyntheticConstantValue"); | 1772 CURRENT_ELEMENT_SPANNABLE, "Unexpected SyntheticConstantValue"); |
1774 } | 1773 } |
1775 } | 1774 } |
1776 | 1775 |
1777 @override | 1776 @override |
1778 void visitDeferred(DeferredConstantValue constant, [_]) { | 1777 void visitDeferred(DeferredConstantValue constant, [_]) { |
1779 addRoot('Deferred'); | 1778 addRoot('Deferred'); |
1780 } | 1779 } |
1781 } | 1780 } |
1782 | 1781 |
1783 /** | 1782 /** |
1784 * Generates canonical hash values for [ConstantValue]s. | 1783 * Generates canonical hash values for [ConstantValue]s. |
1785 * | 1784 * |
1786 * Unfortunately, [Constant.hashCode] is not stable under minor perturbations, | 1785 * Unfortunately, [Constant.hashCode] is not stable under minor perturbations, |
1787 * so it can't be used for generating names. This hasher keeps consistency | 1786 * so it can't be used for generating names. This hasher keeps consistency |
1788 * between runs by basing hash values of the names of elements, rather than | 1787 * between runs by basing hash values of the names of elements, rather than |
1789 * their hashCodes. | 1788 * their hashCodes. |
1790 */ | 1789 */ |
1791 class ConstantCanonicalHasher implements ConstantValueVisitor<int, Null> { | 1790 class ConstantCanonicalHasher implements ConstantValueVisitor<int, Null> { |
1792 | |
1793 static const _MASK = 0x1fffffff; | 1791 static const _MASK = 0x1fffffff; |
1794 static const _UINT32_LIMIT = 4 * 1024 * 1024 * 1024; | 1792 static const _UINT32_LIMIT = 4 * 1024 * 1024 * 1024; |
1795 | 1793 |
1796 | |
1797 final Compiler compiler; | 1794 final Compiler compiler; |
1798 final Map<ConstantValue, int> hashes = new Map<ConstantValue, int>(); | 1795 final Map<ConstantValue, int> hashes = new Map<ConstantValue, int>(); |
1799 | 1796 |
1800 ConstantCanonicalHasher(this.compiler); | 1797 ConstantCanonicalHasher(this.compiler); |
1801 | 1798 |
1802 DiagnosticReporter get reporter => compiler.reporter; | 1799 DiagnosticReporter get reporter => compiler.reporter; |
1803 | 1800 |
1804 int getHash(ConstantValue constant) => _visit(constant); | 1801 int getHash(ConstantValue constant) => _visit(constant); |
1805 | 1802 |
1806 int _visit(ConstantValue constant) { | 1803 int _visit(ConstantValue constant) { |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1919 } | 1916 } |
1920 | 1917 |
1921 static int _hashInt(int value) { | 1918 static int _hashInt(int value) { |
1922 if (value.abs() < _UINT32_LIMIT) return _MASK & value; | 1919 if (value.abs() < _UINT32_LIMIT) return _MASK & value; |
1923 return _hashDouble(value.toDouble()); | 1920 return _hashDouble(value.toDouble()); |
1924 } | 1921 } |
1925 | 1922 |
1926 static int _hashDouble(double value) { | 1923 static int _hashDouble(double value) { |
1927 double magnitude = value.abs(); | 1924 double magnitude = value.abs(); |
1928 int sign = value < 0 ? 1 : 0; | 1925 int sign = value < 0 ? 1 : 0; |
1929 if (magnitude < _UINT32_LIMIT) { // 2^32 | 1926 if (magnitude < _UINT32_LIMIT) { |
| 1927 // 2^32 |
1930 int intValue = value.toInt(); | 1928 int intValue = value.toInt(); |
1931 // Integer valued doubles in 32-bit range hash to the same values as ints. | 1929 // Integer valued doubles in 32-bit range hash to the same values as ints. |
1932 int hash = _hashInt(intValue); | 1930 int hash = _hashInt(intValue); |
1933 if (value == intValue) return hash; | 1931 if (value == intValue) return hash; |
1934 hash = _combine(hash, sign); | 1932 hash = _combine(hash, sign); |
1935 int fraction = ((magnitude - intValue.abs()) * (_MASK + 1)).toInt(); | 1933 int fraction = ((magnitude - intValue.abs()) * (_MASK + 1)).toInt(); |
1936 hash = _combine(hash, fraction); | 1934 hash = _combine(hash, fraction); |
1937 return hash; | 1935 return hash; |
1938 } else if (value.isInfinite) { | 1936 } else if (value.isInfinite) { |
1939 return _combine(6, sign); | 1937 return _combine(6, sign); |
(...skipping 17 matching lines...) Expand all Loading... |
1957 * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function | 1955 * [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function |
1958 */ | 1956 */ |
1959 static int _combine(int hash, int value) { | 1957 static int _combine(int hash, int value) { |
1960 hash = _MASK & (hash + value); | 1958 hash = _MASK & (hash + value); |
1961 hash = _MASK & (hash + (((_MASK >> 10) & hash) << 10)); | 1959 hash = _MASK & (hash + (((_MASK >> 10) & hash) << 10)); |
1962 hash = hash ^ (hash >> 6); | 1960 hash = hash ^ (hash >> 6); |
1963 return hash; | 1961 return hash; |
1964 } | 1962 } |
1965 | 1963 |
1966 static int _finish(int hash) { | 1964 static int _finish(int hash) { |
1967 hash = _MASK & (hash + (((_MASK >> 3) & hash) << 3)); | 1965 hash = _MASK & (hash + (((_MASK >> 3) & hash) << 3)); |
1968 hash = hash & (hash >> 11); | 1966 hash = hash & (hash >> 11); |
1969 return _MASK & (hash + (((_MASK >> 15) & hash) << 15)); | 1967 return _MASK & (hash + (((_MASK >> 15) & hash) << 15)); |
1970 } | 1968 } |
1971 } | 1969 } |
1972 | 1970 |
1973 class FunctionTypeNamer extends BaseDartTypeVisitor { | 1971 class FunctionTypeNamer extends BaseDartTypeVisitor { |
1974 final Compiler compiler; | 1972 final Compiler compiler; |
1975 StringBuffer sb; | 1973 StringBuffer sb; |
1976 | 1974 |
1977 FunctionTypeNamer(this.compiler); | 1975 FunctionTypeNamer(this.compiler); |
(...skipping 19 matching lines...) Expand all Loading... |
1997 sb.write('args${type.parameterTypes.length}'); | 1995 sb.write('args${type.parameterTypes.length}'); |
1998 return; | 1996 return; |
1999 } | 1997 } |
2000 visit(type.returnType); | 1998 visit(type.returnType); |
2001 sb.write('_'); | 1999 sb.write('_'); |
2002 for (DartType parameter in type.parameterTypes) { | 2000 for (DartType parameter in type.parameterTypes) { |
2003 sb.write('_'); | 2001 sb.write('_'); |
2004 visit(parameter); | 2002 visit(parameter); |
2005 } | 2003 } |
2006 bool first = false; | 2004 bool first = false; |
2007 for (DartType parameter in type.optionalParameterTypes) { | 2005 for (DartType parameter in type.optionalParameterTypes) { |
2008 if (!first) { | 2006 if (!first) { |
2009 sb.write('_'); | 2007 sb.write('_'); |
2010 } | 2008 } |
2011 sb.write('_'); | 2009 sb.write('_'); |
2012 visit(parameter); | 2010 visit(parameter); |
2013 first = true; | 2011 first = true; |
2014 } | 2012 } |
2015 if (!type.namedParameterTypes.isEmpty) { | 2013 if (!type.namedParameterTypes.isEmpty) { |
2016 first = false; | 2014 first = false; |
2017 for (DartType parameter in type.namedParameterTypes) { | 2015 for (DartType parameter in type.namedParameterTypes) { |
2018 if (!first) { | 2016 if (!first) { |
2019 sb.write('_'); | 2017 sb.write('_'); |
2020 } | 2018 } |
2021 sb.write('_'); | 2019 sb.write('_'); |
2022 visit(parameter); | 2020 visit(parameter); |
2023 first = true; | 2021 first = true; |
2024 } | 2022 } |
2025 } | 2023 } |
2026 } | 2024 } |
2027 } | 2025 } |
2028 | 2026 |
2029 | |
2030 class NamingScope { | 2027 class NamingScope { |
2031 /// Maps proposed names to *suggested* disambiguated names. | 2028 /// Maps proposed names to *suggested* disambiguated names. |
2032 /// | 2029 /// |
2033 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific | 2030 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific |
2034 /// names be given to the first item with the given proposed name. | 2031 /// names be given to the first item with the given proposed name. |
2035 /// | 2032 /// |
2036 /// This is currently used in [MinifyNamer] to assign very short minified | 2033 /// This is currently used in [MinifyNamer] to assign very short minified |
2037 /// names to things that tend to be used very often. | 2034 /// names to things that tend to be used very often. |
2038 final Map<String, String> _suggestedNames = new Map<String, String>(); | 2035 final Map<String, String> _suggestedNames = new Map<String, String>(); |
2039 final Set<String> _usedNames = new Set<String>(); | 2036 final Set<String> _usedNames = new Set<String>(); |
2040 | 2037 |
2041 bool isUsed(String name) => _usedNames.contains(name); | 2038 bool isUsed(String name) => _usedNames.contains(name); |
2042 bool isUnused(String name) => !_usedNames.contains(name); | 2039 bool isUnused(String name) => !_usedNames.contains(name); |
2043 bool registerUse(String name) => _usedNames.add(name); | 2040 bool registerUse(String name) => _usedNames.add(name); |
2044 | 2041 |
2045 String suggestName(String original) => _suggestedNames[original]; | 2042 String suggestName(String original) => _suggestedNames[original]; |
2046 void addSuggestion(String original, String suggestion) { | 2043 void addSuggestion(String original, String suggestion) { |
2047 assert(!_suggestedNames.containsKey(original)); | 2044 assert(!_suggestedNames.containsKey(original)); |
2048 _suggestedNames[original] = suggestion; | 2045 _suggestedNames[original] = suggestion; |
2049 } | 2046 } |
| 2047 |
2050 bool hasSuggestion(String original) => _suggestedNames.containsKey(original); | 2048 bool hasSuggestion(String original) => _suggestedNames.containsKey(original); |
2051 bool isSuggestion(String candidate) { | 2049 bool isSuggestion(String candidate) { |
2052 return _suggestedNames.containsValue(candidate); | 2050 return _suggestedNames.containsValue(candidate); |
2053 } | 2051 } |
2054 } | 2052 } |
OLD | NEW |