Chromium Code Reviews| 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 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 336 final String methodsWithOptionalArgumentsField = | 336 final String methodsWithOptionalArgumentsField = |
| 337 r'$methodsWithOptionalArguments'; | 337 r'$methodsWithOptionalArguments'; |
| 338 final String deferredAction = r'$deferredAction'; | 338 final String deferredAction = r'$deferredAction'; |
| 339 | 339 |
| 340 final String classDescriptorProperty = r'^'; | 340 final String classDescriptorProperty = r'^'; |
| 341 final String requiredParameterField = r'$requiredArgCount'; | 341 final String requiredParameterField = r'$requiredArgCount'; |
| 342 | 342 |
| 343 /// The non-minifying namer's [callPrefix] with a dollar after it. | 343 /// The non-minifying namer's [callPrefix] with a dollar after it. |
| 344 static const String _callPrefixDollar = r'call$'; | 344 static const String _callPrefixDollar = r'call$'; |
| 345 | 345 |
| 346 static final jsAst.Name literalSuper = new StringBackedName("super"); | |
| 347 static final jsAst.Name literalDollar = new StringBackedName(r'$'); | |
| 348 static final jsAst.Name literalUnderscore = new StringBackedName('_'); | |
| 349 static final jsAst.Name literalPlus = new StringBackedName('+'); | |
| 350 static final jsAst.Name literalDynamic = new StringBackedName("dynamic"); | |
| 351 | |
| 346 // Name of property in a class description for the native dispatch metadata. | 352 // Name of property in a class description for the native dispatch metadata. |
| 347 final String nativeSpecProperty = '%'; | 353 final String nativeSpecProperty = '%'; |
| 348 | 354 |
| 349 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); | 355 static final RegExp IDENTIFIER = new RegExp(r'^[A-Za-z_$][A-Za-z0-9_$]*$'); |
| 350 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); | 356 static final RegExp NON_IDENTIFIER_CHAR = new RegExp(r'[^A-Za-z_0-9$]'); |
| 351 | 357 |
| 352 final Compiler compiler; | 358 final Compiler compiler; |
| 353 | 359 |
| 354 /// Used disambiguated names in the global namespace, issued by | 360 /// Used disambiguated names in the global namespace, issued by |
| 355 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. | 361 /// [_disambiguateGlobal], and [_disambiguateInternalGlobal]. |
| 356 /// | 362 /// |
| 357 /// Although global names are distributed across a number of global objects, | 363 /// Although global names are distributed across a number of global objects, |
| 358 /// (see [globalObjectFor]), we currently use a single namespace for all these | 364 /// (see [globalObjectFor]), we currently use a single namespace for all these |
| 359 /// names. | 365 /// names. |
| 360 final Set<String> usedGlobalNames = new Set<String>(); | 366 final Set<String> usedGlobalNames = new Set<String>(); |
| 361 final Map<Element, String> userGlobals = <Element, String>{}; | 367 final Map<Element, jsAst.Name> userGlobals = |
| 362 final Map<String, String> internalGlobals = <String, String>{}; | 368 new HashMap<Element, jsAst.Name>(); |
| 369 final Map<String, jsAst.Name> internalGlobals = | |
| 370 new HashMap<String, jsAst.Name>(); | |
| 363 | 371 |
| 364 /// Used disambiguated names in the instance namespace, issued by | 372 /// Used disambiguated names in the instance namespace, issued by |
| 365 /// [_disambiguateMember], [_disambiguateInternalMember], | 373 /// [_disambiguateMember], [_disambiguateInternalMember], |
| 366 /// [_disambiguateOperator], and [reservePublicMemberName]. | 374 /// [_disambiguateOperator], and [reservePublicMemberName]. |
| 367 final Set<String> usedInstanceNames = new Set<String>(); | 375 final Set<String> usedInstanceNames = new Set<String>(); |
| 368 final Map<String, String> userInstanceMembers = <String, String>{}; | 376 final Map<String, jsAst.Name> userInstanceMembers = |
| 369 final Map<Element, String> internalInstanceMembers = <Element, String>{}; | 377 new HashMap<String, jsAst.Name>(); |
| 370 final Map<String, String> userInstanceOperators = <String, String>{}; | 378 final Map<Element, jsAst.Name> internalInstanceMembers = |
| 379 new HashMap<Element, jsAst.Name>(); | |
| 380 final Map<String, jsAst.Name> userInstanceOperators = | |
| 381 new HashMap<String, jsAst.Name>(); | |
| 371 | 382 |
| 372 final Map<String, int> popularNameCounters = <String, int>{}; | 383 final Map<String, int> popularNameCounters = <String, int>{}; |
| 373 | 384 |
| 374 final Map<ConstantValue, String> constantNames = <ConstantValue, String>{}; | 385 final Map<LibraryElement, String> libraryLongNames = |
| 386 new HashMap<LibraryElement, String>(); | |
| 387 | |
| 388 final Map<ConstantValue, jsAst.Name> constantNames = | |
| 389 new HashMap<ConstantValue, jsAst.Name>(); | |
| 375 final Map<ConstantValue, String> constantLongNames = | 390 final Map<ConstantValue, String> constantLongNames = |
| 376 <ConstantValue, String>{}; | 391 <ConstantValue, String>{}; |
| 377 ConstantCanonicalHasher constantHasher; | 392 ConstantCanonicalHasher constantHasher; |
| 378 | 393 |
| 379 /// Maps private names to a library that may use that name without prefixing | 394 /// Maps private names to a library that may use that name without prefixing |
| 380 /// itself. Used for building proposed names. | 395 /// itself. Used for building proposed names. |
| 381 final Map<String, LibraryElement> shortPrivateNameOwners = | 396 final Map<String, LibraryElement> shortPrivateNameOwners = |
| 382 <String, LibraryElement>{}; | 397 <String, LibraryElement>{}; |
| 383 | 398 |
| 384 /// Maps proposed names to *suggested* disambiguated names. | 399 /// Maps proposed names to *suggested* disambiguated names. |
| 385 /// | 400 /// |
| 386 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific | 401 /// Suggested names are hints to the [MinifyNamer], suggesting that a specific |
| 387 /// names be given to the first item with the given proposed name. | 402 /// names be given to the first item with the given proposed name. |
| 388 /// | 403 /// |
| 389 /// This is currently used in [MinifyNamer] to assign very short minified | 404 /// This is currently used in [MinifyNamer] to assign very short minified |
| 390 /// names to things that tend to be used very often. | 405 /// names to things that tend to be used very often. |
| 391 final Map<String, String> suggestedGlobalNames = <String, String>{}; | 406 final Map<String, String> suggestedGlobalNames = <String, String>{}; |
| 392 final Map<String, String> suggestedInstanceNames = <String, String>{}; | 407 final Map<String, String> suggestedInstanceNames = <String, String>{}; |
| 393 | 408 |
| 409 /// Used to store unique keys for library names. Keys are not used as names, | |
| 410 /// nor are they visible in the output. The only serve as an internal | |
| 411 /// key into maps. | |
| 412 final Map<LibraryElement, String> _libraryKeys = | |
| 413 new HashMap<LibraryElement, String>(); | |
| 414 | |
| 394 Namer(Compiler compiler) | 415 Namer(Compiler compiler) |
| 395 : compiler = compiler, | 416 : compiler = compiler, |
| 396 constantHasher = new ConstantCanonicalHasher(compiler), | 417 constantHasher = new ConstantCanonicalHasher(compiler), |
| 397 functionTypeNamer = new FunctionTypeNamer(compiler); | 418 functionTypeNamer = new FunctionTypeNamer(compiler); |
| 398 | 419 |
| 399 JavaScriptBackend get backend => compiler.backend; | 420 JavaScriptBackend get backend => compiler.backend; |
| 400 | 421 |
| 401 String get deferredTypesName => 'deferredTypes'; | 422 String get deferredTypesName => 'deferredTypes'; |
| 402 String get isolateName => 'Isolate'; | 423 String get isolateName => 'Isolate'; |
| 403 String get isolatePropertiesName => r'$isolateProperties'; | 424 String get isolatePropertiesName => r'$isolateProperties'; |
| 404 String get noSuchMethodName => publicInstanceMethodNameByArity( | 425 jsAst.Name get noSuchMethodName => publicInstanceMethodNameByArity( |
| 405 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); | 426 Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT); |
| 406 /** | 427 /** |
| 407 * Some closures must contain their name. The name is stored in | 428 * Some closures must contain their name. The name is stored in |
| 408 * [STATIC_CLOSURE_NAME_NAME]. | 429 * [STATIC_CLOSURE_NAME_NAME]. |
| 409 */ | 430 */ |
| 410 String get STATIC_CLOSURE_NAME_NAME => r'$name'; | 431 String get STATIC_CLOSURE_NAME_NAME => r'$name'; |
| 411 String get closureInvocationSelectorName => Compiler.CALL_OPERATOR_NAME; | 432 String get closureInvocationSelectorName => Compiler.CALL_OPERATOR_NAME; |
| 412 bool get shouldMinify => false; | 433 bool get shouldMinify => false; |
| 413 | 434 |
| 414 /// Returns the string that is to be used as the result of a call to | 435 /// Returns the string that is to be used as the result of a call to |
| 415 /// [JS_GET_NAME] at [node] with argument [name]. | 436 /// [JS_GET_NAME] at [node] with argument [name]. |
| 416 String getNameForJsGetName(Node node, JsGetName name) { | 437 jsAst.Name getNameForJsGetName(Node node, JsGetName name) { |
| 417 switch (name) { | 438 switch (name) { |
| 418 case JsGetName.GETTER_PREFIX: return getterPrefix; | 439 case JsGetName.GETTER_PREFIX: return asName(getterPrefix); |
| 419 case JsGetName.SETTER_PREFIX: return setterPrefix; | 440 case JsGetName.SETTER_PREFIX: return asName(setterPrefix); |
| 420 case JsGetName.CALL_PREFIX: return callPrefix; | 441 case JsGetName.CALL_PREFIX: return asName(callPrefix); |
| 421 case JsGetName.CALL_PREFIX0: return '${callPrefix}\$0'; | 442 case JsGetName.CALL_PREFIX0: return asName('${callPrefix}\$0'); |
| 422 case JsGetName.CALL_PREFIX1: return '${callPrefix}\$1'; | 443 case JsGetName.CALL_PREFIX1: return asName('${callPrefix}\$1'); |
| 423 case JsGetName.CALL_PREFIX2: return '${callPrefix}\$2'; | 444 case JsGetName.CALL_PREFIX2: return asName('${callPrefix}\$2'); |
| 424 case JsGetName.CALL_PREFIX3: return '${callPrefix}\$3'; | 445 case JsGetName.CALL_PREFIX3: return asName('${callPrefix}\$3'); |
| 425 case JsGetName.CALL_CATCH_ALL: return callCatchAllName; | 446 case JsGetName.CALL_CATCH_ALL: return asName(callCatchAllName); |
| 426 case JsGetName.REFLECTABLE: return reflectableField; | 447 case JsGetName.REFLECTABLE: return asName(reflectableField); |
| 427 case JsGetName.CLASS_DESCRIPTOR_PROPERTY: | 448 case JsGetName.CLASS_DESCRIPTOR_PROPERTY: |
| 428 return classDescriptorProperty; | 449 return asName(classDescriptorProperty); |
| 429 case JsGetName.REQUIRED_PARAMETER_PROPERTY: | 450 case JsGetName.REQUIRED_PARAMETER_PROPERTY: |
| 430 return requiredParameterField; | 451 return asName(requiredParameterField); |
| 431 case JsGetName.DEFAULT_VALUES_PROPERTY: return defaultValuesField; | 452 case JsGetName.DEFAULT_VALUES_PROPERTY: return asName(defaultValuesField); |
| 432 case JsGetName.CALL_NAME_PROPERTY: return callNameField; | 453 case JsGetName.CALL_NAME_PROPERTY: return asName(callNameField); |
| 433 case JsGetName.DEFERRED_ACTION_PROPERTY: return deferredAction; | 454 case JsGetName.DEFERRED_ACTION_PROPERTY: return asName(deferredAction); |
| 434 case JsGetName.OPERATOR_AS_PREFIX: return operatorAsPrefix; | 455 case JsGetName.OPERATOR_AS_PREFIX: return asName(operatorAsPrefix); |
| 435 case JsGetName.SIGNATURE_NAME: return operatorSignature; | 456 case JsGetName.SIGNATURE_NAME: return asName(operatorSignature); |
| 436 case JsGetName.TYPEDEF_TAG: return typedefTag; | 457 case JsGetName.TYPEDEF_TAG: return asName(typedefTag); |
| 437 case JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG: | 458 case JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG: |
| 438 return functionTypeVoidReturnTag; | 459 return asName(functionTypeVoidReturnTag); |
| 439 case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG: | 460 case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG: |
| 440 return functionTypeReturnTypeTag; | 461 return asName(functionTypeReturnTypeTag); |
| 441 case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG: | 462 case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG: |
| 442 return functionTypeRequiredParametersTag; | 463 return asName(functionTypeRequiredParametersTag); |
| 443 case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG: | 464 case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG: |
| 444 return functionTypeOptionalParametersTag; | 465 return asName(functionTypeOptionalParametersTag); |
| 445 case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG: | 466 case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG: |
| 446 return functionTypeNamedParametersTag; | 467 return asName(functionTypeNamedParametersTag); |
| 447 case JsGetName.IS_INDEXABLE_FIELD_NAME: | 468 case JsGetName.IS_INDEXABLE_FIELD_NAME: |
| 448 Element cls = backend.findHelper('JavaScriptIndexingBehavior'); | 469 Element cls = backend.findHelper('JavaScriptIndexingBehavior'); |
| 449 return operatorIs(cls); | 470 return operatorIs(cls); |
| 471 case JsGetName.NULL_CLASS_TYPE_NAME: | |
| 472 return runtimeTypeName(compiler.nullClass); | |
| 473 case JsGetName.OBJECT_CLASS_TYPE_NAME: | |
| 474 return runtimeTypeName(compiler.objectClass); | |
| 475 case JsGetName.FUNCTION_CLASS_TYPE_NAME: | |
| 476 return runtimeTypeName(compiler.functionClass); | |
| 450 default: | 477 default: |
| 451 compiler.reportError( | 478 compiler.reportError( |
| 452 node, MessageKind.GENERIC, | 479 node, MessageKind.GENERIC, |
| 453 {'text': 'Error: Namer has no name for "$name".'}); | 480 {'text': 'Error: Namer has no name for "$name".'}); |
| 454 return 'BROKEN'; | 481 return asName('BROKEN'); |
| 455 } | 482 } |
| 456 } | 483 } |
| 457 | 484 |
| 458 /// Disambiguated name for [constant]. | 485 /// Disambiguated name for [constant]. |
| 459 /// | 486 /// |
| 460 /// Unique within the global-member namespace. | 487 /// Unique within the global-member namespace. |
| 461 String constantName(ConstantValue constant) { | 488 jsAst.Name constantName(ConstantValue constant) { |
| 462 // In the current implementation it doesn't make sense to give names to | 489 // In the current implementation it doesn't make sense to give names to |
| 463 // function constants since the function-implementation itself serves as | 490 // function constants since the function-implementation itself serves as |
| 464 // constant and can be accessed directly. | 491 // constant and can be accessed directly. |
| 465 assert(!constant.isFunction); | 492 assert(!constant.isFunction); |
| 466 String result = constantNames[constant]; | 493 jsAst.Name result = constantNames[constant]; |
| 467 if (result == null) { | 494 if (result == null) { |
| 468 String longName = constantLongName(constant); | 495 String longName = constantLongName(constant); |
| 469 result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames); | 496 result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames); |
| 470 constantNames[constant] = result; | 497 constantNames[constant] = result; |
| 471 } | 498 } |
| 472 return result; | 499 return result; |
| 473 } | 500 } |
| 474 | 501 |
| 475 /// Proposed name for [constant]. | 502 /// Proposed name for [constant]. |
| 476 String constantLongName(ConstantValue constant) { | 503 String constantLongName(ConstantValue constant) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 523 // The first library asking for a short private name wins. | 550 // The first library asking for a short private name wins. |
| 524 LibraryElement owner = | 551 LibraryElement owner = |
| 525 shortPrivateNameOwners.putIfAbsent(text, () => library); | 552 shortPrivateNameOwners.putIfAbsent(text, () => library); |
| 526 | 553 |
| 527 if (owner == library) { | 554 if (owner == library) { |
| 528 return text; | 555 return text; |
| 529 } else { | 556 } else { |
| 530 // Make sure to return a private name that starts with _ so it | 557 // Make sure to return a private name that starts with _ so it |
| 531 // cannot clash with any public names. | 558 // cannot clash with any public names. |
| 532 // The name is still not guaranteed to be unique, since both the library | 559 // The name is still not guaranteed to be unique, since both the library |
| 533 // name and originalName could contain $ symbols. | 560 // name and originalName could contain $ symbols and as the library |
| 534 String libraryName = _disambiguateGlobal(library); | 561 // name itself might clash. |
| 535 return '_$libraryName\$${text}'; | 562 String libraryName = _proposeNameForGlobal(library); |
| 563 return "_$libraryName\$$text"; | |
| 536 } | 564 } |
| 537 } | 565 } |
| 538 | 566 |
| 539 String _proposeNameForConstructorBody(ConstructorBodyElement method) { | 567 _proposeNameForConstructorBody(ConstructorBodyElement method) { |
|
floitsch
2015/06/22 17:43:44
returns a String.
herhut
2015/06/23 13:26:30
Done.
| |
| 540 String name = Elements.reconstructConstructorNameSourceString(method); | 568 String name = Elements.reconstructConstructorNameSourceString(method); |
| 541 // We include the method suffix on constructor bodies. It has no purpose, | 569 // We include the method suffix on constructor bodies. It has no purpose, |
| 542 // but this way it produces the same names as previous versions of the | 570 // but this way it produces the same names as previous versions of the |
| 543 // Namer class did. | 571 // Namer class did. |
| 544 List<String> suffix = callSuffixForSignature(method.functionSignature); | 572 List<String> suffix = callSuffixForSignature(method.functionSignature); |
| 545 return '$name\$${suffix.join(r'$')}'; | 573 return '$name\$${suffix.join(r'$')}'; |
| 546 } | 574 } |
| 547 | 575 |
| 548 /// Annotated name for [method] encoding arity and named parameters. | 576 /// Annotated name for [method] encoding arity and named parameters. |
| 549 String instanceMethodName(FunctionElement method) { | 577 jsAst.Name instanceMethodName(FunctionElement method) { |
| 550 if (method.isGenerativeConstructorBody) { | 578 if (method.isGenerativeConstructorBody) { |
| 551 return _disambiguateInternalMember(method, | 579 return _disambiguateInternalMember(method, |
| 552 () => _proposeNameForConstructorBody(method)); | 580 () => _proposeNameForConstructorBody(method)); |
| 553 } | 581 } |
| 554 return invocationName(new Selector.fromElement(method)); | 582 return invocationName(new Selector.fromElement(method)); |
| 555 } | 583 } |
| 556 | 584 |
| 557 /// Annotated name for a public method with the given [originalName] | 585 /// Annotated name for a public method with the given [originalName] |
| 558 /// and [arity] and no named parameters. | 586 /// and [arity] and no named parameters. |
| 559 String publicInstanceMethodNameByArity(String originalName, int arity) { | 587 jsAst.Name publicInstanceMethodNameByArity(String originalName, |
| 588 int arity) { | |
|
floitsch
2015/06/22 17:43:44
indentation.
herhut
2015/06/23 13:26:30
Done.
| |
| 560 return invocationName(new Selector.call(originalName, null, arity)); | 589 return invocationName(new Selector.call(originalName, null, arity)); |
| 561 } | 590 } |
| 562 | 591 |
| 563 /// Returns the annotated name for a variant of `call`. | 592 /// Returns the annotated name for a variant of `call`. |
| 564 /// The result has the form: | 593 /// The result has the form: |
| 565 /// | 594 /// |
| 566 /// call$<N>$namedParam1...$namedParam<M> | 595 /// call$<N>$namedParam1...$namedParam<M> |
| 567 /// | 596 /// |
| 568 /// This name cannot be minified because it is generated by string | 597 /// This name cannot be minified because it is generated by string |
| 569 /// concatenation at runtime, by applyFunction in js_helper.dart. | 598 /// concatenation at runtime, by applyFunction in js_helper.dart. |
| 570 String deriveCallMethodName(List<String> suffix) { | 599 jsAst.Name deriveCallMethodName(List<String> suffix) { |
| 571 // TODO(asgerf): Avoid clashes when named parameters contain $ symbols. | 600 // TODO(asgerf): Avoid clashes when named parameters contain $ symbols. |
| 572 return '$callPrefix\$${suffix.join(r'$')}'; | 601 return new StringBackedName('$callPrefix\$${suffix.join(r'$')}'); |
| 573 } | 602 } |
| 574 | 603 |
| 575 /// The suffix list for the pattern: | 604 /// The suffix list for the pattern: |
| 576 /// | 605 /// |
| 577 /// $<N>$namedParam1...$namedParam<M> | 606 /// $<N>$namedParam1...$namedParam<M> |
| 578 /// | 607 /// |
| 579 /// This is used for the annotated names of `call`, and for the proposed name | 608 /// This is used for the annotated names of `call`, and for the proposed name |
| 580 /// for other instance methods. | 609 /// for other instance methods. |
| 581 List<String> callSuffixForStructure(CallStructure callStructure) { | 610 List<String> callSuffixForStructure(CallStructure callStructure) { |
| 582 List<String> suffixes = ['${callStructure.argumentCount}']; | 611 List<String> suffixes = ['${callStructure.argumentCount}']; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 594 List<String> suffixes = ['${sig.parameterCount}']; | 623 List<String> suffixes = ['${sig.parameterCount}']; |
| 595 if (sig.optionalParametersAreNamed) { | 624 if (sig.optionalParametersAreNamed) { |
| 596 for (FormalElement param in sig.orderedOptionalParameters) { | 625 for (FormalElement param in sig.orderedOptionalParameters) { |
| 597 suffixes.add(param.name); | 626 suffixes.add(param.name); |
| 598 } | 627 } |
| 599 } | 628 } |
| 600 return suffixes; | 629 return suffixes; |
| 601 } | 630 } |
| 602 | 631 |
| 603 /// Annotated name for the member being invoked by [selector]. | 632 /// Annotated name for the member being invoked by [selector]. |
| 604 String invocationName(Selector selector) { | 633 jsAst.Name invocationName(Selector selector) { |
| 605 switch (selector.kind) { | 634 switch (selector.kind) { |
| 606 case SelectorKind.GETTER: | 635 case SelectorKind.GETTER: |
| 607 String disambiguatedName = _disambiguateMember(selector.memberName); | 636 jsAst.Name disambiguatedName = |
| 637 _disambiguateMember(selector.memberName); | |
| 608 return deriveGetterName(disambiguatedName); | 638 return deriveGetterName(disambiguatedName); |
| 609 | 639 |
| 610 case SelectorKind.SETTER: | 640 case SelectorKind.SETTER: |
| 611 String disambiguatedName = _disambiguateMember(selector.memberName); | 641 jsAst.Name disambiguatedName = |
| 642 _disambiguateMember(selector.memberName); | |
| 612 return deriveSetterName(disambiguatedName); | 643 return deriveSetterName(disambiguatedName); |
| 613 | 644 |
| 614 case SelectorKind.OPERATOR: | 645 case SelectorKind.OPERATOR: |
| 615 case SelectorKind.INDEX: | 646 case SelectorKind.INDEX: |
| 616 String operatorIdentifier = operatorNameToIdentifier(selector.name); | 647 String operatorIdentifier = operatorNameToIdentifier(selector.name); |
| 617 String disambiguatedName = _disambiguateOperator(operatorIdentifier); | 648 jsAst.Name disambiguatedName = |
| 649 _disambiguateOperator(operatorIdentifier); | |
| 618 return disambiguatedName; // Operators are not annotated. | 650 return disambiguatedName; // Operators are not annotated. |
| 619 | 651 |
| 620 case SelectorKind.CALL: | 652 case SelectorKind.CALL: |
| 621 List<String> suffix = callSuffixForStructure(selector.callStructure); | 653 List<String> suffix = callSuffixForStructure(selector.callStructure); |
| 622 if (selector.name == Compiler.CALL_OPERATOR_NAME) { | 654 if (selector.name == Compiler.CALL_OPERATOR_NAME) { |
| 623 // Derive the annotated name for this variant of 'call'. | 655 // Derive the annotated name for this variant of 'call'. |
| 624 return deriveCallMethodName(suffix); | 656 return deriveCallMethodName(suffix); |
| 625 } | 657 } |
| 626 String disambiguatedName = | 658 jsAst.Name disambiguatedName = |
| 627 _disambiguateMember(selector.memberName, suffix); | 659 _disambiguateMember(selector.memberName, suffix); |
| 628 return disambiguatedName; // Methods other than call are not annotated. | 660 return disambiguatedName; // Methods other than call are not annotated. |
| 629 | 661 |
| 630 default: | 662 default: |
| 631 compiler.internalError(compiler.currentElement, | 663 compiler.internalError(compiler.currentElement, |
| 632 'Unexpected selector kind: ${selector.kind}'); | 664 'Unexpected selector kind: ${selector.kind}'); |
| 633 return null; | 665 return null; |
| 634 } | 666 } |
| 635 } | 667 } |
| 636 | 668 |
| 637 /** | 669 /** |
| 638 * Returns the internal name used for an invocation mirror of this selector. | 670 * Returns the internal name used for an invocation mirror of this selector. |
| 639 */ | 671 */ |
| 640 String invocationMirrorInternalName(Selector selector) | 672 jsAst.Name invocationMirrorInternalName(Selector selector) |
| 641 => invocationName(selector); | 673 => invocationName(selector); |
| 642 | 674 |
| 643 /** | 675 /** |
| 644 * Returns the disambiguated name for the given field, used for constructing | 676 * Returns the disambiguated name for the given field, used for constructing |
| 645 * the getter and setter names. | 677 * the getter and setter names. |
| 646 */ | 678 */ |
| 647 String fieldAccessorName(FieldElement element) { | 679 jsAst.Name fieldAccessorName(FieldElement element) { |
| 648 return element.isInstanceMember | 680 return element.isInstanceMember |
| 649 ? _disambiguateMember(element.memberName) | 681 ? _disambiguateMember(element.memberName) |
| 650 : _disambiguateGlobal(element); | 682 : _disambiguateGlobal(element); |
| 651 } | 683 } |
| 652 | 684 |
| 653 /** | 685 /** |
| 654 * Returns name of the JavaScript property used to store a static or instance | 686 * Returns name of the JavaScript property used to store a static or instance |
| 655 * field. | 687 * field. |
| 656 */ | 688 */ |
| 657 String fieldPropertyName(FieldElement element) { | 689 jsAst.Name fieldPropertyName(FieldElement element) { |
| 658 return element.isInstanceMember | 690 return element.isInstanceMember |
| 659 ? instanceFieldPropertyName(element) | 691 ? instanceFieldPropertyName(element) |
| 660 : _disambiguateGlobal(element); | 692 : _disambiguateGlobal(element); |
| 661 } | 693 } |
| 662 | 694 |
| 663 /** | 695 /** |
| 664 * Returns name of the JavaScript property used to store the | 696 * Returns name of the JavaScript property used to store the |
| 665 * `readTypeVariable` function for the given type variable. | 697 * `readTypeVariable` function for the given type variable. |
| 666 */ | 698 */ |
| 667 String nameForReadTypeVariable(TypeVariableElement element) { | 699 jsAst.Name nameForReadTypeVariable(TypeVariableElement element) { |
| 668 return _disambiguateInternalMember(element, () => element.name); | 700 return _disambiguateInternalMember(element, () => element.name); |
| 669 } | 701 } |
| 670 | 702 |
| 671 /** | 703 /** |
| 672 * Returns a JavaScript property name used to store [element] on one | 704 * Returns a JavaScript property name used to store [element] on one |
| 673 * of the global objects. | 705 * of the global objects. |
| 674 * | 706 * |
| 675 * Should be used together with [globalObjectFor], which denotes the object | 707 * Should be used together with [globalObjectFor], which denotes the object |
| 676 * on which the returned property name should be used. | 708 * on which the returned property name should be used. |
| 677 */ | 709 */ |
| 678 String globalPropertyName(Element element) { | 710 jsAst.Name globalPropertyName(Element element) { |
| 679 return _disambiguateGlobal(element); | 711 return _disambiguateGlobal(element); |
| 680 } | 712 } |
| 681 | 713 |
| 682 /** | 714 /** |
| 683 * Returns the JavaScript property name used to store an instance field. | 715 * Returns the JavaScript property name used to store an instance field. |
| 684 */ | 716 */ |
| 685 String instanceFieldPropertyName(FieldElement element) { | 717 jsAst.Name instanceFieldPropertyName(FieldElement element) { |
| 686 ClassElement enclosingClass = element.enclosingClass; | 718 ClassElement enclosingClass = element.enclosingClass; |
| 687 | 719 |
| 688 if (element.hasFixedBackendName) { | 720 if (element.hasFixedBackendName) { |
| 689 // Certain native fields must be given a specific name. Native names must | 721 // Certain native fields must be given a specific name. Native names must |
| 690 // not contain '$'. We rely on this to avoid clashes. | 722 // not contain '$'. We rely on this to avoid clashes. |
| 691 assert(enclosingClass.isNative && | 723 assert(enclosingClass.isNative && |
| 692 !element.fixedBackendName.contains(r'$')); | 724 !element.fixedBackendName.contains(r'$')); |
| 693 | 725 |
| 694 return element.fixedBackendName; | 726 return new StringBackedName(element.fixedBackendName); |
| 695 } | 727 } |
| 696 | 728 |
| 697 // Instances of BoxFieldElement are special. They are already created with | 729 // Instances of BoxFieldElement are special. They are already created with |
| 698 // a unique and safe name. However, as boxes are not really instances of | 730 // a unique and safe name. However, as boxes are not really instances of |
| 699 // classes, the usual naming scheme that tries to avoid name clashes with | 731 // classes, the usual naming scheme that tries to avoid name clashes with |
| 700 // super classes does not apply. We still do not mark the name as a | 732 // super classes does not apply. We still do not mark the name as a |
| 701 // fixedBackendName, as we want to allow other namers to do something more | 733 // fixedBackendName, as we want to allow other namers to do something more |
| 702 // clever with them. | 734 // clever with them. |
| 703 if (element is BoxFieldElement) { | 735 if (element is BoxFieldElement) { |
| 704 return element.name; | 736 return new StringBackedName(element.name); |
| 705 } | 737 } |
| 706 | 738 |
| 707 // If the name of the field might clash with another field, | 739 // If the name of the field might clash with another field, |
| 708 // use a mangled field name to avoid potential clashes. | 740 // use a mangled field name to avoid potential clashes. |
| 709 // Note that if the class extends a native class, that native class might | 741 // Note that if the class extends a native class, that native class might |
| 710 // have fields with fixed backend names, so we assume the worst and always | 742 // have fields with fixed backend names, so we assume the worst and always |
| 711 // mangle the field names of classes extending native classes. | 743 // mangle the field names of classes extending native classes. |
| 712 // Methods on such classes are stored on the interceptor, not the instance, | 744 // Methods on such classes are stored on the interceptor, not the instance, |
| 713 // so only fields have the potential to clash with a native property name. | 745 // so only fields have the potential to clash with a native property name. |
| 714 ClassWorld classWorld = compiler.world; | 746 ClassWorld classWorld = compiler.world; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 729 return element.enclosingClass.hasFieldShadowedBy(element); | 761 return element.enclosingClass.hasFieldShadowedBy(element); |
| 730 } | 762 } |
| 731 | 763 |
| 732 /// True if [class_] is a non-native class that inherits from a native class. | 764 /// True if [class_] is a non-native class that inherits from a native class. |
| 733 bool _isUserClassExtendingNative(ClassElement class_) { | 765 bool _isUserClassExtendingNative(ClassElement class_) { |
| 734 return !class_.isNative && | 766 return !class_.isNative && |
| 735 Elements.isNativeOrExtendsNative(class_.superclass); | 767 Elements.isNativeOrExtendsNative(class_.superclass); |
| 736 } | 768 } |
| 737 | 769 |
| 738 /// Annotated name for the setter of [element]. | 770 /// Annotated name for the setter of [element]. |
| 739 String setterForElement(MemberElement element) { | 771 jsAst.Name setterForElement(MemberElement element) { |
| 740 // We dynamically create setters from the field-name. The setter name must | 772 // We dynamically create setters from the field-name. The setter name must |
| 741 // therefore be derived from the instance field-name. | 773 // therefore be derived from the instance field-name. |
| 742 String name = _disambiguateMember(element.memberName); | 774 jsAst.Name name = _disambiguateMember(element.memberName); |
| 743 return deriveSetterName(name); | 775 return deriveSetterName(name); |
| 744 } | 776 } |
| 745 | 777 |
| 746 /// Annotated name for the setter of any member with [disambiguatedName]. | 778 /// Annotated name for the setter of any member with [disambiguatedName]. |
| 747 String deriveSetterName(String disambiguatedName) { | 779 jsAst.Name deriveSetterName(jsAst.Name disambiguatedName) { |
| 748 // We dynamically create setters from the field-name. The setter name must | 780 // We dynamically create setters from the field-name. The setter name must |
| 749 // therefore be derived from the instance field-name. | 781 // therefore be derived from the instance field-name. |
| 750 return '$setterPrefix$disambiguatedName'; | 782 return new SetterName(new StringBackedName(setterPrefix), |
|
sra1
2015/06/23 04:47:54
The prefix should probably be cached.
herhut
2015/06/23 13:26:30
Done.
| |
| 783 disambiguatedName); | |
| 751 } | 784 } |
| 752 | 785 |
| 753 /// Annotated name for the setter of any member with [disambiguatedName]. | 786 /// Annotated name for the setter of any member with [disambiguatedName]. |
| 754 String deriveGetterName(String disambiguatedName) { | 787 jsAst.Name deriveGetterName(jsAst.Name disambiguatedName) { |
| 755 // We dynamically create getters from the field-name. The getter name must | 788 // We dynamically create getters from the field-name. The getter name must |
| 756 // therefore be derived from the instance field-name. | 789 // therefore be derived from the instance field-name. |
| 757 return '$getterPrefix$disambiguatedName'; | 790 return new GetterName(new StringBackedName(getterPrefix), |
| 791 disambiguatedName); | |
| 758 } | 792 } |
| 759 | 793 |
| 760 /// Annotated name for the getter of [element]. | 794 /// Annotated name for the getter of [element]. |
| 761 String getterForElement(MemberElement element) { | 795 jsAst.Name getterForElement(MemberElement element) { |
| 762 // We dynamically create getters from the field-name. The getter name must | 796 // We dynamically create getters from the field-name. The getter name must |
| 763 // therefore be derived from the instance field-name. | 797 // therefore be derived from the instance field-name. |
| 764 String name = _disambiguateMember(element.memberName); | 798 jsAst.Name name = _disambiguateMember(element.memberName); |
| 765 return deriveGetterName(name); | 799 return deriveGetterName(name); |
| 766 } | 800 } |
| 767 | 801 |
| 768 /// Property name for the getter of an instance member with [originalName]. | 802 /// Property name for the getter of an instance member with [originalName]. |
| 769 String getterForMember(Name originalName) { | 803 jsAst.Name getterForMember(Name originalName) { |
| 770 String disambiguatedName = _disambiguateMember(originalName); | 804 jsAst.Name disambiguatedName = _disambiguateMember(originalName); |
| 771 return deriveGetterName(disambiguatedName); | 805 return deriveGetterName(disambiguatedName); |
| 772 } | 806 } |
| 773 | 807 |
| 774 /// Disambiguated name for a compiler-owned global variable. | 808 /// Disambiguated name for a compiler-owned global variable. |
| 775 /// | 809 /// |
| 776 /// The resulting name is unique within the global-member namespace. | 810 /// The resulting name is unique within the global-member namespace. |
| 777 String _disambiguateInternalGlobal(String name) { | 811 jsAst.Name _disambiguateInternalGlobal(String name) { |
| 778 String newName = internalGlobals[name]; | 812 jsAst.Name newName = internalGlobals[name]; |
| 779 if (newName == null) { | 813 if (newName == null) { |
| 780 newName = getFreshName(name, usedGlobalNames, suggestedGlobalNames); | 814 newName = getFreshName(name, usedGlobalNames, suggestedGlobalNames); |
| 781 internalGlobals[name] = newName; | 815 internalGlobals[name] = newName; |
| 782 } | 816 } |
| 783 return newName; | 817 return newName; |
| 784 } | 818 } |
| 785 | 819 |
| 786 /// Returns the property name to use for a compiler-owner global variable, | 820 /// Returns the property name to use for a compiler-owner global variable, |
| 787 /// i.e. one that does not correspond to any element but is used as a utility | 821 /// i.e. one that does not correspond to any element but is used as a utility |
| 788 /// global by code generation. | 822 /// global by code generation. |
| 789 /// | 823 /// |
| 790 /// [name] functions as both the proposed name for the global, and as a key | 824 /// [name] functions as both the proposed name for the global, and as a key |
| 791 /// identifying the global. The [name] must not contain `$` symbols, since | 825 /// identifying the global. The [name] must not contain `$` symbols, since |
| 792 /// the [Namer] uses those names internally. | 826 /// the [Namer] uses those names internally. |
| 793 /// | 827 /// |
| 794 /// This provides an easy mechanism of avoiding a name-clash with user-space | 828 /// This provides an easy mechanism of avoiding a name-clash with user-space |
| 795 /// globals, although the callers of must still take care not to accidentally | 829 /// globals, although the callers of must still take care not to accidentally |
| 796 /// pass in the same [name] for two different internal globals. | 830 /// pass in the same [name] for two different internal globals. |
| 797 String internalGlobal(String name) { | 831 jsAst.Name internalGlobal(String name) { |
| 798 assert(!name.contains(r'$')); | 832 assert(!name.contains(r'$')); |
| 799 return _disambiguateInternalGlobal(name); | 833 return _disambiguateInternalGlobal(name); |
| 800 } | 834 } |
| 801 | 835 |
| 836 /// Generates a unique key for [library]. | |
| 837 /// | |
| 838 /// Keys are meant to be used in maps and should not be visible in the output. | |
| 839 String _generateLibraryKey(LibraryElement library) { | |
| 840 return _libraryKeys.putIfAbsent(library, () { | |
| 841 String keyBase = library.name; | |
| 842 int counter = 0; | |
| 843 String key = keyBase; | |
| 844 while (_libraryKeys.values.contains(key)) { | |
| 845 key ="$keyBase${counter++}"; | |
| 846 } | |
| 847 return key; | |
| 848 }); | |
| 849 } | |
| 850 | |
| 802 /// Returns the disambiguated name for a top-level or static element. | 851 /// Returns the disambiguated name for a top-level or static element. |
| 803 /// | 852 /// |
| 804 /// The resulting name is unique within the global-member namespace. | 853 /// The resulting name is unique within the global-member namespace. |
| 805 String _disambiguateGlobal(Element element) { | 854 jsAst.Name _disambiguateGlobal(Element element) { |
| 806 // TODO(asgerf): We can reuse more short names if we disambiguate with | 855 // TODO(asgerf): We can reuse more short names if we disambiguate with |
| 807 // a separate namespace for each of the global holder objects. | 856 // a separate namespace for each of the global holder objects. |
| 808 element = element.declaration; | 857 element = element.declaration; |
| 809 String newName = userGlobals[element]; | 858 jsAst.Name newName = userGlobals[element]; |
| 810 if (newName == null) { | 859 if (newName == null) { |
| 811 String proposedName = _proposeNameForGlobal(element); | 860 String proposedName = _proposeNameForGlobal(element); |
| 812 newName = getFreshName(proposedName, usedGlobalNames, | 861 newName = getFreshName(proposedName, usedGlobalNames, |
| 813 suggestedGlobalNames); | 862 suggestedGlobalNames); |
| 814 userGlobals[element] = newName; | 863 userGlobals[element] = newName; |
| 815 } | 864 } |
| 816 return newName; | 865 return newName; |
| 817 } | 866 } |
| 818 | 867 |
| 819 /// Returns the disambiguated name for an instance method or field | 868 /// Returns the disambiguated name for an instance method or field |
| 820 /// with [originalName] in [library]. | 869 /// with [originalName] in [library]. |
| 821 /// | 870 /// |
| 822 /// [library] may be `null` if [originalName] is known to be public. | 871 /// [library] may be `null` if [originalName] is known to be public. |
| 823 /// | 872 /// |
| 824 /// This is the name used for deriving property names of accessors (getters | 873 /// This is the name used for deriving property names of accessors (getters |
| 825 /// and setters) and as property name for storing methods and method stubs. | 874 /// and setters) and as property name for storing methods and method stubs. |
| 826 /// | 875 /// |
| 827 /// [suffixes] denote an extension of [originalName] to distiguish it from | 876 /// [suffixes] denote an extension of [originalName] to distiguish it from |
| 828 /// other members with that name. These are used to encode the arity and | 877 /// other members with that name. These are used to encode the arity and |
| 829 /// named parameters to a method. Disambiguating the same [originalName] with | 878 /// named parameters to a method. Disambiguating the same [originalName] with |
| 830 /// different [suffixes] will yield different disambiguated names. | 879 /// different [suffixes] will yield different disambiguated names. |
| 831 /// | 880 /// |
| 832 /// The resulting name, and its associated annotated names, are unique | 881 /// The resulting name, and its associated annotated names, are unique |
| 833 /// to the ([originalName], [suffixes]) pair within the instance-member | 882 /// to the ([originalName], [suffixes]) pair within the instance-member |
| 834 /// namespace. | 883 /// namespace. |
| 835 String _disambiguateMember(Name originalName, | 884 jsAst.Name _disambiguateMember(Name originalName, |
| 836 [List<String> suffixes = const []]) { | 885 [List<String> suffixes = const []]) { |
| 837 // Build a string encoding the library name, if the name is private. | 886 // Build a string encoding the library name, if the name is private. |
| 838 String libraryKey = originalName.isPrivate | 887 String libraryKey = originalName.isPrivate |
| 839 ? _disambiguateGlobal(originalName.library) | 888 ? _generateLibraryKey(originalName.library) |
| 840 : ''; | 889 : ''; |
| 841 | 890 |
| 842 // In the unique key, separate the name parts by '@'. | 891 // In the unique key, separate the name parts by '@'. |
| 843 // This avoids clashes since the original names cannot contain that symbol. | 892 // This avoids clashes since the original names cannot contain that symbol. |
| 844 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; | 893 String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}'; |
| 845 String newName = userInstanceMembers[key]; | 894 jsAst.Name newName = userInstanceMembers[key]; |
| 846 if (newName == null) { | 895 if (newName == null) { |
| 847 String proposedName = privateName(originalName); | 896 String proposedName = privateName(originalName); |
| 848 if (!suffixes.isEmpty) { | 897 if (!suffixes.isEmpty) { |
| 849 // In the proposed name, separate the name parts by '$', because the | 898 // In the proposed name, separate the name parts by '$', because the |
| 850 // proposed name must be a valid identifier, but not necessarily unique. | 899 // proposed name must be a valid identifier, but not necessarily unique. |
| 851 proposedName += r'$' + suffixes.join(r'$'); | 900 proposedName += r'$' + suffixes.join(r'$'); |
| 852 } | 901 } |
| 853 newName = getFreshName(proposedName, | 902 newName = getFreshName(proposedName, |
| 854 usedInstanceNames, suggestedInstanceNames, | 903 usedInstanceNames, suggestedInstanceNames, |
| 855 sanitizeForAnnotations: true); | 904 sanitizeForAnnotations: true); |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 867 /// Using [_disambiguateMember] with the given [originalName] and no suffixes | 916 /// Using [_disambiguateMember] with the given [originalName] and no suffixes |
| 868 /// will subsequently return [disambiguatedName]. | 917 /// will subsequently return [disambiguatedName]. |
| 869 void reservePublicMemberName(String originalName, | 918 void reservePublicMemberName(String originalName, |
| 870 String disambiguatedName) { | 919 String disambiguatedName) { |
| 871 // Build a key that corresponds to the one built in disambiguateMember. | 920 // Build a key that corresponds to the one built in disambiguateMember. |
| 872 String libraryPrefix = ''; // Public names have an empty library prefix. | 921 String libraryPrefix = ''; // Public names have an empty library prefix. |
| 873 String suffix = ''; // We don't need any suffixes. | 922 String suffix = ''; // We don't need any suffixes. |
| 874 String key = '$libraryPrefix@$originalName@$suffix'; | 923 String key = '$libraryPrefix@$originalName@$suffix'; |
| 875 assert(!userInstanceMembers.containsKey(key)); | 924 assert(!userInstanceMembers.containsKey(key)); |
| 876 assert(!usedInstanceNames.contains(disambiguatedName)); | 925 assert(!usedInstanceNames.contains(disambiguatedName)); |
| 877 userInstanceMembers[key] = disambiguatedName; | 926 userInstanceMembers[key] = new StringBackedName(disambiguatedName); |
| 878 usedInstanceNames.add(disambiguatedName); | 927 usedInstanceNames.add(disambiguatedName); |
| 879 } | 928 } |
| 880 | 929 |
| 881 /// Disambiguated name unique to [element]. | 930 /// Disambiguated name unique to [element]. |
| 882 /// | 931 /// |
| 883 /// This is used as the property name for fields, type variables, | 932 /// This is used as the property name for fields, type variables, |
| 884 /// constructor bodies, and super-accessors. | 933 /// constructor bodies, and super-accessors. |
| 885 /// | 934 /// |
| 886 /// The resulting name is unique within the instance-member namespace. | 935 /// The resulting name is unique within the instance-member namespace. |
| 887 String _disambiguateInternalMember(Element element, String proposeName()) { | 936 jsAst.Name _disambiguateInternalMember(Element element, |
| 888 String newName = internalInstanceMembers[element]; | 937 String proposeName()) { |
| 938 jsAst.Name newName = internalInstanceMembers[element]; | |
| 889 if (newName == null) { | 939 if (newName == null) { |
| 890 String name = proposeName(); | 940 String name = proposeName(); |
| 891 bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass); | 941 bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass); |
| 892 newName = getFreshName(name, | 942 newName = getFreshName(name, |
| 893 usedInstanceNames, suggestedInstanceNames, | 943 usedInstanceNames, suggestedInstanceNames, |
| 894 sanitizeForAnnotations: true, | 944 sanitizeForAnnotations: true, |
| 895 sanitizeForNatives: mayClashNative); | 945 sanitizeForNatives: mayClashNative); |
| 896 internalInstanceMembers[element] = newName; | 946 internalInstanceMembers[element] = newName; |
| 897 } | 947 } |
| 898 return newName; | 948 return newName; |
| 899 } | 949 } |
| 900 | 950 |
| 901 /// Disambiguated name for the given operator. | 951 /// Disambiguated name for the given operator. |
| 902 /// | 952 /// |
| 903 /// [operatorIdentifier] must be the operator's identifier, e.g. | 953 /// [operatorIdentifier] must be the operator's identifier, e.g. |
| 904 /// `$add` and not `+`. | 954 /// `$add` and not `+`. |
| 905 /// | 955 /// |
| 906 /// The resulting name is unique within the instance-member namespace. | 956 /// The resulting name is unique within the instance-member namespace. |
| 907 String _disambiguateOperator(String operatorIdentifier) { | 957 jsAst.Name _disambiguateOperator(String operatorIdentifier) { |
| 908 String newName = userInstanceOperators[operatorIdentifier]; | 958 jsAst.Name newName = userInstanceOperators[operatorIdentifier]; |
| 909 if (newName == null) { | 959 if (newName == null) { |
| 910 newName = getFreshName(operatorIdentifier, usedInstanceNames, | 960 newName = getFreshName(operatorIdentifier, usedInstanceNames, |
| 911 suggestedInstanceNames); | 961 suggestedInstanceNames); |
| 912 userInstanceOperators[operatorIdentifier] = newName; | 962 userInstanceOperators[operatorIdentifier] = newName; |
| 913 } | 963 } |
| 914 return newName; | 964 return newName; |
| 915 } | 965 } |
| 916 | 966 |
| 917 /// Returns an unused name. | 967 /// Returns an unused name. |
| 918 /// | 968 /// |
| 919 /// [proposedName] must be a valid JavaScript identifier. | 969 /// [proposedName] must be a valid JavaScript identifier. |
| 920 /// | 970 /// |
| 921 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not | 971 /// If [sanitizeForAnnotations] is `true`, then the result is guaranteed not |
| 922 /// to have the form of an annotated name. | 972 /// to have the form of an annotated name. |
| 923 /// | 973 /// |
| 924 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to | 974 /// If [sanitizeForNatives] it `true`, then the result is guaranteed not to |
| 925 /// clash with a property name on a native object. | 975 /// clash with a property name on a native object. |
| 926 /// | 976 /// |
| 927 /// Note that [MinifyNamer] overrides this method with one that produces | 977 /// Note that [MinifyNamer] overrides this method with one that produces |
| 928 /// minified names. | 978 /// minified names. |
| 929 String getFreshName(String proposedName, | 979 jsAst.Name getFreshName(String proposedName, |
| 930 Set<String> usedNames, | 980 Set<String> usedNames, |
| 931 Map<String, String> suggestedNames, | 981 Map<String, String> suggestedNames, |
| 932 {bool sanitizeForAnnotations: false, | 982 {bool sanitizeForAnnotations: false, |
| 933 bool sanitizeForNatives: false}) { | 983 bool sanitizeForNatives: false}) { |
| 934 if (sanitizeForAnnotations) { | 984 if (sanitizeForAnnotations) { |
| 935 proposedName = _sanitizeForAnnotations(proposedName); | 985 proposedName = _sanitizeForAnnotations(proposedName); |
| 936 } | 986 } |
| 937 if (sanitizeForNatives) { | 987 if (sanitizeForNatives) { |
| 938 proposedName = _sanitizeForNatives(proposedName); | 988 proposedName = _sanitizeForNatives(proposedName); |
| 939 } | 989 } |
| 940 proposedName = _sanitizeForKeywords(proposedName); | 990 proposedName = _sanitizeForKeywords(proposedName); |
| 941 String candidate; | 991 String candidate; |
| 942 if (!usedNames.contains(proposedName)) { | 992 if (!usedNames.contains(proposedName)) { |
| 943 candidate = proposedName; | 993 candidate = proposedName; |
| 944 } else { | 994 } else { |
| 945 int counter = popularNameCounters[proposedName]; | 995 int counter = popularNameCounters[proposedName]; |
| 946 int i = (counter == null) ? 0 : counter; | 996 int i = (counter == null) ? 0 : counter; |
| 947 while (usedNames.contains("$proposedName$i")) { | 997 while (usedNames.contains("$proposedName$i")) { |
| 948 i++; | 998 i++; |
| 949 } | 999 } |
| 950 popularNameCounters[proposedName] = i + 1; | 1000 popularNameCounters[proposedName] = i + 1; |
| 951 candidate = "$proposedName$i"; | 1001 candidate = "$proposedName$i"; |
| 952 } | 1002 } |
| 953 usedNames.add(candidate); | 1003 usedNames.add(candidate); |
| 954 return candidate; | 1004 return new StringBackedName(candidate); |
| 955 } | 1005 } |
| 956 | 1006 |
| 957 /// Returns a variant of [name] that cannot clash with the annotated | 1007 /// Returns a variant of [name] that cannot clash with the annotated |
| 958 /// version of another name, that is, the resulting name can never be returned | 1008 /// version of another name, that is, the resulting name can never be returned |
| 959 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], | 1009 /// by [deriveGetterName], [deriveSetterName], [deriveCallMethodName], |
| 960 /// [operatorIs], or [substitutionName]. | 1010 /// [operatorIs], or [substitutionName]. |
| 961 /// | 1011 /// |
| 962 /// For example, a name `get$x` would be converted to `$get$x` to ensure it | 1012 /// For example, a name `get$x` would be converted to `$get$x` to ensure it |
| 963 /// cannot clash with the getter for `x`. | 1013 /// cannot clash with the getter for `x`. |
| 964 /// | 1014 /// |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1010 } else if (Elements.isStaticOrTopLevel(element)) { | 1060 } else if (Elements.isStaticOrTopLevel(element)) { |
| 1011 if (element.isClassMember) { | 1061 if (element.isClassMember) { |
| 1012 ClassElement enclosingClass = element.enclosingClass; | 1062 ClassElement enclosingClass = element.enclosingClass; |
| 1013 name = "${enclosingClass.name}_" | 1063 name = "${enclosingClass.name}_" |
| 1014 "${element.name}"; | 1064 "${element.name}"; |
| 1015 } else { | 1065 } else { |
| 1016 name = element.name.replaceAll('+', '_'); | 1066 name = element.name.replaceAll('+', '_'); |
| 1017 } | 1067 } |
| 1018 } else if (element.isLibrary) { | 1068 } else if (element.isLibrary) { |
| 1019 LibraryElement library = element; | 1069 LibraryElement library = element; |
| 1070 name = libraryLongNames[library]; | |
| 1071 if (name != null) return name; | |
| 1020 name = library.getLibraryOrScriptName(); | 1072 name = library.getLibraryOrScriptName(); |
| 1021 if (name.contains('.')) { | 1073 if (name.contains('.')) { |
| 1022 // For libraries that have a library tag, we use the last part | 1074 // For libraries that have a library tag, we use the last part |
| 1023 // of the fully qualified name as their base name. For all other | 1075 // of the fully qualified name as their base name. For all other |
| 1024 // libraries, we use the first part of their filename. | 1076 // libraries, we use the first part of their filename. |
| 1025 name = library.hasLibraryName() | 1077 name = library.hasLibraryName() |
| 1026 ? name.substring(name.lastIndexOf('.') + 1) | 1078 ? name.substring(name.lastIndexOf('.') + 1) |
| 1027 : name.substring(0, name.indexOf('.')); | 1079 : name.substring(0, name.indexOf('.')); |
| 1028 } | 1080 } |
| 1029 // The filename based name can contain all kinds of nasty characters. Make | 1081 // The filename based name can contain all kinds of nasty characters. Make |
| 1030 // sure it is an identifier. | 1082 // sure it is an identifier. |
| 1031 if (!IDENTIFIER.hasMatch(name)) { | 1083 if (!IDENTIFIER.hasMatch(name)) { |
| 1032 name = name.replaceAllMapped(NON_IDENTIFIER_CHAR, | 1084 name = name.replaceAllMapped(NON_IDENTIFIER_CHAR, |
| 1033 (match) => match[0].codeUnitAt(0).toRadixString(16)); | 1085 (match) => match[0].codeUnitAt(0).toRadixString(16)); |
| 1034 if (!IDENTIFIER.hasMatch(name)) { // e.g. starts with digit. | 1086 if (!IDENTIFIER.hasMatch(name)) { // e.g. starts with digit. |
| 1035 name = 'lib_$name'; | 1087 name = 'lib_$name'; |
| 1036 } | 1088 } |
| 1037 } | 1089 } |
| 1090 // Names constructed based on a libary name will be further disambiguated. | |
| 1091 // However, as names from the same libary should have the same libary | |
| 1092 // name part, we disambiguate the library name here. | |
| 1093 String disambiguated = name; | |
| 1094 for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) { | |
| 1095 disambiguated = "$name$c"; | |
| 1096 } | |
| 1097 libraryLongNames[library] = disambiguated; | |
| 1098 name = disambiguated; | |
| 1038 } else { | 1099 } else { |
| 1039 name = element.name; | 1100 name = element.name; |
| 1040 } | 1101 } |
| 1041 return name; | 1102 return name; |
| 1042 } | 1103 } |
| 1043 | 1104 |
| 1044 String suffixForGetInterceptor(Iterable<ClassElement> classes) { | 1105 String suffixForGetInterceptor(Iterable<ClassElement> classes) { |
| 1045 String abbreviate(ClassElement cls) { | 1106 String abbreviate(ClassElement cls) { |
| 1046 if (cls == compiler.objectClass) return "o"; | 1107 if (cls == compiler.objectClass) return "o"; |
| 1047 if (cls == backend.jsStringClass) return "s"; | 1108 if (cls == backend.jsStringClass) return "s"; |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1062 if (classes.any((cls) => Elements.isNativeOrExtendsNative(cls))) { | 1123 if (classes.any((cls) => Elements.isNativeOrExtendsNative(cls))) { |
| 1063 names.add("x"); | 1124 names.add("x"); |
| 1064 } | 1125 } |
| 1065 // Sort the names of the classes after abbreviating them to ensure | 1126 // Sort the names of the classes after abbreviating them to ensure |
| 1066 // the suffix is stable and predictable for the suggested names. | 1127 // the suffix is stable and predictable for the suggested names. |
| 1067 names.sort(); | 1128 names.sort(); |
| 1068 return names.join(); | 1129 return names.join(); |
| 1069 } | 1130 } |
| 1070 | 1131 |
| 1071 /// Property name used for `getInterceptor` or one of its specializations. | 1132 /// Property name used for `getInterceptor` or one of its specializations. |
| 1072 String nameForGetInterceptor(Iterable<ClassElement> classes) { | 1133 jsAst.Name nameForGetInterceptor(Iterable<ClassElement> classes) { |
| 1073 FunctionElement getInterceptor = backend.getInterceptorMethod; | 1134 FunctionElement getInterceptor = backend.getInterceptorMethod; |
| 1074 if (classes.contains(backend.jsInterceptorClass)) { | 1135 if (classes.contains(backend.jsInterceptorClass)) { |
| 1075 // If the base Interceptor class is in the set of intercepted classes, we | 1136 // If the base Interceptor class is in the set of intercepted classes, we |
| 1076 // need to go through the generic getInterceptorMethod, since any subclass | 1137 // need to go through the generic getInterceptorMethod, since any subclass |
| 1077 // of the base Interceptor could match. | 1138 // of the base Interceptor could match. |
| 1078 // The unspecialized getInterceptor method can also be accessed through | 1139 // The unspecialized getInterceptor method can also be accessed through |
| 1079 // its element, so we treat this as a user-space global instead of an | 1140 // its element, so we treat this as a user-space global instead of an |
| 1080 // internal global. | 1141 // internal global. |
| 1081 return _disambiguateGlobal(getInterceptor); | 1142 return _disambiguateGlobal(getInterceptor); |
| 1082 } | 1143 } |
| 1083 String suffix = suffixForGetInterceptor(classes); | 1144 String suffix = suffixForGetInterceptor(classes); |
| 1084 return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix"); | 1145 return _disambiguateInternalGlobal("${getInterceptor.name}\$$suffix"); |
| 1085 } | 1146 } |
| 1086 | 1147 |
| 1087 /// Property name used for the one-shot interceptor method for the given | 1148 /// Property name used for the one-shot interceptor method for the given |
| 1088 /// [selector] and return-type specialization. | 1149 /// [selector] and return-type specialization. |
| 1089 String nameForGetOneShotInterceptor(Selector selector, | 1150 jsAst.Name nameForGetOneShotInterceptor(Selector selector, |
| 1090 Iterable<ClassElement> classes) { | 1151 Iterable<ClassElement> classes) { |
| 1091 // The one-shot name is a global name derived from the invocation name. To | 1152 // The one-shot name is a global name derived from the invocation name. To |
| 1092 // avoid instability we would like the names to be unique and not clash with | 1153 // avoid instability we would like the names to be unique and not clash with |
| 1093 // other global names. | 1154 // other global names. |
| 1094 | 1155 |
| 1095 String root = invocationName(selector); | 1156 jsAst.Name root = invocationName(selector); |
| 1096 | 1157 |
| 1097 if (classes.contains(backend.jsInterceptorClass)) { | 1158 if (classes.contains(backend.jsInterceptorClass)) { |
| 1098 // If the base Interceptor class is in the set of intercepted classes, | 1159 // If the base Interceptor class is in the set of intercepted classes, |
| 1099 // this is the most general specialization which uses the generic | 1160 // this is the most general specialization which uses the generic |
| 1100 // getInterceptor method. To keep the name short, we add '$' only to | 1161 // getInterceptor method. To keep the name short, we add '$' only to |
| 1101 // distinguish from internal globals requested from outside the Namer | 1162 // distinguish from internal globals requested from outside the Namer |
| 1102 // with internalGlobal(). | 1163 // with internalGlobal(). |
| 1103 // TODO(sra): Find a way to get the simple name when Object is not in the | 1164 // TODO(sra): Find a way to get the simple name when Object is not in the |
| 1104 // set of classes for most general variant, e.g. "$lt$n" could be "$lt". | 1165 // set of classes for most general variant, e.g. "$lt$n" could be "$lt". |
| 1105 if (selector.isGetter || selector.isSetter) root = '$root\$'; | 1166 if (selector.isGetter || selector.isSetter) { |
| 1106 return _disambiguateInternalGlobal(root); | 1167 return new CompoundName([root, literalDollar]); |
| 1168 } else { | |
| 1169 return root; | |
| 1170 } | |
| 1107 } else { | 1171 } else { |
| 1108 String suffix = suffixForGetInterceptor(classes); | 1172 String suffix = suffixForGetInterceptor(classes); |
| 1109 return _disambiguateInternalGlobal("$root\$$suffix"); | 1173 return new CompoundName([root, literalDollar, |
| 1174 new StringBackedName(suffix)]); | |
| 1110 } | 1175 } |
| 1111 } | 1176 } |
| 1112 | 1177 |
| 1113 /// Returns the runtime name for [element]. | 1178 /// Returns the runtime name for [element]. |
| 1114 /// | 1179 /// |
| 1115 /// This name is used as the basis for deriving `is` and `as` property names | 1180 /// This name is used as the basis for deriving `is` and `as` property names |
| 1116 /// for the given type. | 1181 /// for the given type. |
| 1117 /// | 1182 /// |
| 1118 /// The result is not always safe as a property name unless prefixing | 1183 /// The result is not always safe as a property name unless prefixing |
| 1119 /// [operatorIsPrefix] or [operatorAsPrefix]. If this is a function type, | 1184 /// [operatorIsPrefix] or [operatorAsPrefix]. If this is a function type, |
| 1120 /// then by convention, an underscore must also separate [operatorIsPrefix] | 1185 /// then by convention, an underscore must also separate [operatorIsPrefix] |
| 1121 /// from the type name. | 1186 /// from the type name. |
| 1122 String runtimeTypeName(TypeDeclarationElement element) { | 1187 jsAst.Name runtimeTypeName(TypeDeclarationElement element) { |
| 1123 if (element == null) return 'dynamic'; | 1188 if (element == null) return literalDynamic; |
| 1124 // The returned name affects both the global and instance member namespaces: | 1189 // The returned name affects both the global and instance member namespaces: |
| 1125 // | 1190 // |
| 1126 // - If given a class, this must coincide with the class name, which | 1191 // - If given a class, this must coincide with the class name, which |
| 1127 // is also the GLOBAL property name of its constructor. | 1192 // is also the GLOBAL property name of its constructor. |
| 1128 // | 1193 // |
| 1129 // - The result is used to derive `$isX` and `$asX` names, which are used | 1194 // - The result is used to derive `$isX` and `$asX` names, which are used |
| 1130 // as INSTANCE property names. | 1195 // as INSTANCE property names. |
| 1131 // | 1196 // |
| 1132 // To prevent clashes in both namespaces at once, we disambiguate the name | 1197 // To prevent clashes in both namespaces at once, we disambiguate the name |
| 1133 // as a global here, and in [_sanitizeForAnnotations] we ensure that | 1198 // as a global here, and in [_sanitizeForAnnotations] we ensure that |
| 1134 // ordinary instance members cannot start with `$is` or `$as`. | 1199 // ordinary instance members cannot start with `$is` or `$as`. |
| 1135 return _disambiguateGlobal(element); | 1200 return _disambiguateGlobal(element); |
| 1136 } | 1201 } |
| 1137 | 1202 |
| 1138 /// Returns the disambiguated name of [class_]. | 1203 /// Returns the disambiguated name of [class_]. |
| 1139 /// | 1204 /// |
| 1140 /// This is both the *runtime type* of the class (see [runtimeTypeName]) | 1205 /// This is both the *runtime type* of the class (see [runtimeTypeName]) |
| 1141 /// and a global property name in which to store its JS constructor. | 1206 /// and a global property name in which to store its JS constructor. |
| 1142 String className(ClassElement class_) => _disambiguateGlobal(class_); | 1207 jsAst.Name className(ClassElement class_) => _disambiguateGlobal(class_); |
| 1143 | 1208 |
| 1144 /// Property name on which [member] can be accessed directly, | 1209 /// Property name on which [member] can be accessed directly, |
| 1145 /// without clashing with another JS property name. | 1210 /// without clashing with another JS property name. |
| 1146 /// | 1211 /// |
| 1147 /// This is used for implementing super-calls, where ordinary dispatch | 1212 /// This is used for implementing super-calls, where ordinary dispatch |
| 1148 /// semantics must be circumvented. For example: | 1213 /// semantics must be circumvented. For example: |
| 1149 /// | 1214 /// |
| 1150 /// class A { foo() } | 1215 /// class A { foo() } |
| 1151 /// class B extends A { | 1216 /// class B extends A { |
| 1152 /// foo() { super.foo() } | 1217 /// foo() { super.foo() } |
| 1153 /// } | 1218 /// } |
| 1154 /// | 1219 /// |
| 1155 /// Example translation to JS: | 1220 /// Example translation to JS: |
| 1156 /// | 1221 /// |
| 1157 /// A.prototype.super$A$foo = function() {...} | 1222 /// A.prototype.super$A$foo = function() {...} |
| 1158 /// A.prototype.foo$0 = A.prototype.super$A$foo | 1223 /// A.prototype.foo$0 = A.prototype.super$A$foo |
| 1159 /// | 1224 /// |
| 1160 /// B.prototype.foo$0 = function() { | 1225 /// B.prototype.foo$0 = function() { |
| 1161 /// this.super$A$foo(); // super.foo() | 1226 /// this.super$A$foo(); // super.foo() |
| 1162 /// } | 1227 /// } |
| 1163 /// | 1228 /// |
| 1164 String aliasedSuperMemberPropertyName(Element member) { | 1229 jsAst.Name aliasedSuperMemberPropertyName(Element member) { |
| 1165 assert(!member.isField); // Fields do not need super aliases. | 1230 assert(!member.isField); // Fields do not need super aliases. |
| 1166 String methodName = instanceMethodName(member); | 1231 return _disambiguateInternalMember(member, () { |
| 1167 return _disambiguateInternalMember(member, | 1232 String invocationName = operatorNameToIdentifier(member.name); |
| 1168 () => 'super\$${member.enclosingClass.name}\$$methodName'); | 1233 return "super\$${member.enclosingClass.name}\$$invocationName"; |
| 1234 }); | |
| 1169 } | 1235 } |
| 1170 | 1236 |
| 1171 /// Property name in which to store the given static or instance [method]. | 1237 /// Property name in which to store the given static or instance [method]. |
| 1172 /// For instance methods, this includes the suffix encoding arity and named | 1238 /// For instance methods, this includes the suffix encoding arity and named |
| 1173 /// parameters. | 1239 /// parameters. |
| 1174 /// | 1240 /// |
| 1175 /// The name is not necessarily unique to [method], since a static method | 1241 /// The name is not necessarily unique to [method], since a static method |
| 1176 /// may share its name with an instance method. | 1242 /// may share its name with an instance method. |
| 1177 String methodPropertyName(Element method) { | 1243 jsAst.Name methodPropertyName(Element method) { |
| 1178 return method.isInstanceMember | 1244 return method.isInstanceMember |
| 1179 ? instanceMethodName(method) | 1245 ? instanceMethodName(method) |
| 1180 : globalPropertyName(method); | 1246 : globalPropertyName(method); |
| 1181 } | 1247 } |
| 1182 | 1248 |
| 1183 /// Returns true if [element] is stored on current isolate ('$'). We intend | 1249 /// Returns true if [element] is stored on current isolate ('$'). We intend |
| 1184 /// to store only mutable static state in [currentIsolate], constants are | 1250 /// to store only mutable static state in [currentIsolate], constants are |
| 1185 /// stored in 'C', and functions, accessors, classes, etc. are stored in one | 1251 /// stored in 'C', and functions, accessors, classes, etc. are stored in one |
| 1186 /// of the other objects in [reservedGlobalObjectNames]. | 1252 /// of the other objects in [reservedGlobalObjectNames]. |
| 1187 bool isPropertyOfCurrentIsolate(Element element) { | 1253 bool isPropertyOfCurrentIsolate(Element element) { |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1206 if (library == backend.interceptorsLibrary) return 'J'; | 1272 if (library == backend.interceptorsLibrary) return 'J'; |
| 1207 if (library.isInternalLibrary) return 'H'; | 1273 if (library.isInternalLibrary) return 'H'; |
| 1208 if (library.isPlatformLibrary) { | 1274 if (library.isPlatformLibrary) { |
| 1209 if ('${library.canonicalUri}' == 'dart:html') return 'W'; | 1275 if ('${library.canonicalUri}' == 'dart:html') return 'W'; |
| 1210 return 'P'; | 1276 return 'P'; |
| 1211 } | 1277 } |
| 1212 return userGlobalObjects[ | 1278 return userGlobalObjects[ |
| 1213 library.getLibraryOrScriptName().hashCode % userGlobalObjects.length]; | 1279 library.getLibraryOrScriptName().hashCode % userGlobalObjects.length]; |
| 1214 } | 1280 } |
| 1215 | 1281 |
| 1216 String lazyInitializerName(Element element) { | 1282 jsAst.Name lazyInitializerName(Element element) { |
| 1217 assert(Elements.isStaticOrTopLevelField(element)); | 1283 assert(Elements.isStaticOrTopLevelField(element)); |
| 1218 String name = _disambiguateGlobal(element); | 1284 jsAst.Name name = _disambiguateGlobal(element); |
| 1219 return _disambiguateInternalGlobal("$getterPrefix$name"); | 1285 // Why do we need to disambiguate here? |
|
floitsch
2015/06/22 17:43:44
Maybe I'm missing something, but I think you can h
herhut
2015/06/23 13:26:30
Good point. Fixed.
| |
| 1286 // return _disambiguateInternalGlobal("$getterPrefix$name"); | |
| 1287 return deriveGetterName(name); | |
| 1220 } | 1288 } |
| 1221 | 1289 |
| 1222 String staticClosureName(Element element) { | 1290 jsAst.Name staticClosureName(Element element) { |
| 1223 assert(Elements.isStaticOrTopLevelFunction(element)); | 1291 assert(Elements.isStaticOrTopLevelFunction(element)); |
| 1224 String name = _disambiguateGlobal(element); | 1292 String enclosing = element.enclosingClass == null |
| 1225 return _disambiguateInternalGlobal("$name\$closure"); | 1293 ? "" : element.enclosingClass.name; |
| 1294 String library = _proposeNameForGlobal(element.library); | |
| 1295 return _disambiguateInternalGlobal( | |
| 1296 "${library}_${enclosing}_${element.name}\$closure"); | |
| 1226 } | 1297 } |
| 1227 | 1298 |
| 1228 // This name is used as part of the name of a TypeConstant | 1299 // This name is used as part of the name of a TypeConstant |
| 1229 String uniqueNameForTypeConstantElement(Element element) { | 1300 String uniqueNameForTypeConstantElement(Element element) { |
| 1230 // TODO(sra): If we replace the period with an identifier character, | 1301 // TODO(sra): If we replace the period with an identifier character, |
| 1231 // TypeConstants will have better names in unminified code. | 1302 // TypeConstants will have better names in unminified code. |
| 1232 return "${globalObjectFor(element)}.${globalPropertyName(element)}"; | 1303 String library = _proposeNameForGlobal(element.library); |
| 1304 return "${library}.${element.name}"; | |
| 1233 } | 1305 } |
| 1234 | 1306 |
| 1235 String globalObjectForConstant(ConstantValue constant) => 'C'; | 1307 String globalObjectForConstant(ConstantValue constant) => 'C'; |
| 1236 | 1308 |
| 1237 String get operatorIsPrefix => r'$is'; | 1309 String get operatorIsPrefix => r'$is'; |
| 1238 | 1310 |
| 1239 String get operatorAsPrefix => r'$as'; | 1311 String get operatorAsPrefix => r'$as'; |
| 1240 | 1312 |
| 1241 String get operatorSignature => r'$signature'; | 1313 String get operatorSignature => r'$signature'; |
| 1242 | 1314 |
| 1243 String get typedefTag => r'typedef'; | 1315 String get typedefTag => r'typedef'; |
| 1244 | 1316 |
| 1245 String get functionTypeTag => r'func'; | 1317 String get functionTypeTag => r'func'; |
| 1246 | 1318 |
| 1247 String get functionTypeVoidReturnTag => r'void'; | 1319 String get functionTypeVoidReturnTag => r'void'; |
| 1248 | 1320 |
| 1249 String get functionTypeReturnTypeTag => r'ret'; | 1321 String get functionTypeReturnTypeTag => r'ret'; |
| 1250 | 1322 |
| 1251 String get functionTypeRequiredParametersTag => r'args'; | 1323 String get functionTypeRequiredParametersTag => r'args'; |
| 1252 | 1324 |
| 1253 String get functionTypeOptionalParametersTag => r'opt'; | 1325 String get functionTypeOptionalParametersTag => r'opt'; |
| 1254 | 1326 |
| 1255 String get functionTypeNamedParametersTag => r'named'; | 1327 String get functionTypeNamedParametersTag => r'named'; |
| 1256 | 1328 |
| 1257 Map<FunctionType,String> functionTypeNameMap = | 1329 Map<FunctionType, jsAst.Name> functionTypeNameMap = |
| 1258 new Map<FunctionType,String>(); | 1330 new HashMap<FunctionType, jsAst.Name>(); |
| 1259 final FunctionTypeNamer functionTypeNamer; | 1331 final FunctionTypeNamer functionTypeNamer; |
| 1260 | 1332 |
| 1261 String getFunctionTypeName(FunctionType functionType) { | 1333 jsAst.Name getFunctionTypeName(FunctionType functionType) { |
| 1262 return functionTypeNameMap.putIfAbsent(functionType, () { | 1334 return functionTypeNameMap.putIfAbsent(functionType, () { |
| 1263 String proposedName = functionTypeNamer.computeName(functionType); | 1335 String proposedName = functionTypeNamer.computeName(functionType); |
| 1264 String freshName = getFreshName(proposedName, usedInstanceNames, | 1336 return getFreshName(proposedName, usedInstanceNames, |
| 1265 suggestedInstanceNames); | 1337 suggestedInstanceNames); |
| 1266 return freshName; | |
| 1267 }); | 1338 }); |
| 1268 } | 1339 } |
| 1269 | 1340 |
| 1270 String operatorIsType(DartType type) { | 1341 jsAst.Name operatorIsType(DartType type) { |
| 1271 if (type.isFunctionType) { | 1342 if (type.isFunctionType) { |
| 1272 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. | 1343 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. |
| 1273 return '${operatorIsPrefix}_${getFunctionTypeName(type)}'; | 1344 return new CompoundName([new StringBackedName(operatorIsPrefix), |
| 1345 literalUnderscore, | |
| 1346 getFunctionTypeName(type)]); | |
| 1274 } | 1347 } |
| 1275 return operatorIs(type.element); | 1348 return operatorIs(type.element); |
| 1276 } | 1349 } |
| 1277 | 1350 |
| 1278 String operatorIs(ClassElement element) { | 1351 jsAst.Name operatorIs(ClassElement element) { |
| 1279 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. | 1352 // TODO(erikcorry): Reduce from $isx to ix when we are minifying. |
| 1280 return '${operatorIsPrefix}${runtimeTypeName(element)}'; | 1353 return new CompoundName([new StringBackedName(operatorIsPrefix), |
| 1354 runtimeTypeName(element)]); | |
| 1281 } | 1355 } |
| 1282 | 1356 |
| 1283 /// Returns a name that does not clash with reserved JS keywords. | 1357 /// Returns a name that does not clash with reserved JS keywords. |
| 1284 String _sanitizeForKeywords(String name) { | 1358 String _sanitizeForKeywords(String name) { |
| 1285 if (jsReserved.contains(name)) { | 1359 if (jsReserved.contains(name)) { |
| 1286 name = '\$$name'; | 1360 name = '\$$name'; |
| 1287 } | 1361 } |
| 1288 assert(!jsReserved.contains(name)); | 1362 assert(!jsReserved.contains(name)); |
| 1289 return name; | 1363 return name; |
| 1290 } | 1364 } |
| 1291 | 1365 |
| 1292 String substitutionName(Element element) { | 1366 jsAst.Name substitutionName(Element element) { |
| 1293 return '${operatorAsPrefix}${runtimeTypeName(element)}'; | 1367 return new CompoundName([new StringBackedName(operatorAsPrefix), |
| 1368 runtimeTypeName(element)]); | |
| 1369 } | |
| 1370 | |
| 1371 /// Translates a [String] into the corresponding [Name] data structure as | |
| 1372 /// used by the namer. | |
| 1373 /// | |
| 1374 /// If [name] is a setter or getter name, the corresponding [GetterName] or | |
|
floitsch
2015/06/22 17:43:44
That shouldn't be necessary for static names. (unl
herhut
2015/06/23 13:26:30
This is mostly used in testing (as otherwise one c
| |
| 1375 /// [SetterName] data structure is used. | |
| 1376 jsAst.Name asName(String name) { | |
| 1377 if (name.startsWith(getterPrefix) && name.length > getterPrefix.length) { | |
| 1378 return new GetterName(new StringBackedName(getterPrefix), | |
| 1379 new StringBackedName( | |
| 1380 name.substring(getterPrefix.length))); | |
| 1381 } | |
| 1382 if (name.startsWith(setterPrefix) && name.length > setterPrefix.length) { | |
| 1383 return new GetterName(new StringBackedName(setterPrefix), | |
| 1384 new StringBackedName( | |
| 1385 name.substring(setterPrefix.length))); | |
| 1386 } | |
| 1387 | |
| 1388 return new StringBackedName(name); | |
| 1294 } | 1389 } |
| 1295 | 1390 |
| 1296 /// Returns a variable name that cannot clash with a keyword, a global | 1391 /// Returns a variable name that cannot clash with a keyword, a global |
| 1297 /// variable, or any name starting with a single '$'. | 1392 /// variable, or any name starting with a single '$'. |
| 1298 /// | 1393 /// |
| 1299 /// Furthermore, this function is injective, that is, it never returns the | 1394 /// Furthermore, this function is injective, that is, it never returns the |
| 1300 /// same name for two different inputs. | 1395 /// same name for two different inputs. |
| 1301 String safeVariableName(String name) { | 1396 String safeVariableName(String name) { |
| 1302 if (jsVariableReserved.contains(name) || name.startsWith(r'$')) { | 1397 if (jsVariableReserved.contains(name) || name.startsWith(r'$')) { |
| 1303 return '\$$name'; | 1398 return '\$$name'; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1352 } | 1447 } |
| 1353 } | 1448 } |
| 1354 | 1449 |
| 1355 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; | 1450 String get incrementalHelperName => r'$dart_unsafe_incremental_support'; |
| 1356 | 1451 |
| 1357 jsAst.Expression get accessIncrementalHelper { | 1452 jsAst.Expression get accessIncrementalHelper { |
| 1358 return js('self.${incrementalHelperName}'); | 1453 return js('self.${incrementalHelperName}'); |
| 1359 } | 1454 } |
| 1360 | 1455 |
| 1361 void forgetElement(Element element) { | 1456 void forgetElement(Element element) { |
| 1362 String globalName = userGlobals[element]; | 1457 jsAst.Name globalName = userGlobals[element]; |
| 1363 invariant(element, globalName != null, message: 'No global name.'); | 1458 invariant(element, globalName != null, message: 'No global name.'); |
| 1364 usedGlobalNames.remove(globalName); | 1459 usedGlobalNames.remove(globalName); |
| 1365 userGlobals.remove(element); | 1460 userGlobals.remove(element); |
| 1366 } | 1461 } |
| 1367 } | 1462 } |
| 1368 | 1463 |
| 1464 abstract class _NamerName extends jsAst.Name { | |
| 1465 int get _kind; | |
| 1466 } | |
| 1467 | |
| 1468 class StringBackedName extends _NamerName { | |
| 1469 final String name; | |
| 1470 final int _kind = 1; | |
|
sra1
2015/06/23 04:47:54
int get _kind => 1;
Otherwise you are still doing
herhut
2015/06/23 13:26:30
Done.
| |
| 1471 | |
| 1472 StringBackedName(this.name); | |
| 1473 | |
| 1474 toString() => throw new UnsupportedError("Cannot convert a name to a string"); | |
| 1475 | |
| 1476 operator==(other) => (other is StringBackedName) && other.name == name; | |
|
sra1
2015/06/23 04:47:54
Is the purpose of ==, hashCode and compareTo?
Are
herhut
2015/06/23 13:26:30
Yes. However, typically only instances of StingBac
| |
| 1477 | |
| 1478 int get hashCode => name.hashCode; | |
| 1479 | |
| 1480 int compareTo(other) { | |
| 1481 if (other is! _NamerName) return -1; | |
|
sra1
2015/06/23 04:47:54
Since you can't make the other implementation of N
herhut
2015/06/23 13:26:30
Done.
| |
| 1482 if (other._kind != _kind) return other._kind - _kind; | |
| 1483 return name.compareTo(other.name); | |
| 1484 } | |
| 1485 } | |
| 1486 | |
| 1487 abstract class _PrefixedName extends _NamerName { | |
| 1488 final jsAst.Name prefix; | |
| 1489 final jsAst.Name base; | |
| 1490 int get _kind; | |
|
sra1
2015/06/23 04:47:54
Somewhat redundant with _NamerName._kind.
Leave it
herhut
2015/06/23 13:26:31
Removed.
| |
| 1491 | |
| 1492 _PrefixedName(this.prefix, this.base); | |
| 1493 | |
| 1494 String get name => prefix.name + base.name; | |
| 1495 | |
| 1496 toString() => throw new UnsupportedError("Cannot convert a name to a string"); | |
| 1497 | |
| 1498 operator==(other) { | |
| 1499 if (other is! _PrefixedName) return false; | |
| 1500 return other.base == base && other.prefix == prefix; | |
| 1501 } | |
| 1502 | |
| 1503 int get hashCode => base.hashCode * 13 + prefix.hashCode; | |
| 1504 | |
| 1505 int compareTo(other) { | |
| 1506 if (other is! _NamerName) return -1; | |
| 1507 if (other._kind != _kind) return other._kind - _kind; | |
| 1508 int result = prefix.compareTo(other.prefix); | |
| 1509 if (result == 0) { | |
| 1510 result = name.compareTo(other.name); | |
| 1511 } | |
| 1512 return result; | |
| 1513 } | |
| 1514 } | |
| 1515 | |
| 1516 class GetterName extends _PrefixedName { | |
| 1517 final int _kind = 2; | |
| 1518 | |
| 1519 GetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base); | |
| 1520 } | |
| 1521 | |
| 1522 class SetterName extends _PrefixedName { | |
| 1523 final int _kind = 3; | |
| 1524 | |
| 1525 SetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base); | |
| 1526 } | |
| 1527 | |
| 1528 class CompoundName extends _NamerName { | |
| 1529 final List<_NamerName> _parts; | |
| 1530 final int _kind = 4; | |
| 1531 String _cachedName; | |
| 1532 int _cachedHashCode = -1; | |
| 1533 | |
| 1534 CompoundName(this._parts); | |
| 1535 | |
| 1536 String get name { | |
| 1537 if (_cachedName == null) { | |
| 1538 _cachedName = _parts.map((jsAst.Name name) => name.name).join(); | |
| 1539 } | |
| 1540 return _cachedName; | |
| 1541 } | |
| 1542 | |
| 1543 toString() => throw new UnsupportedError("Cannot convert a name to a string"); | |
| 1544 | |
| 1545 operator==(other) { | |
|
floitsch
2015/06/22 17:43:44
bool
herhut
2015/06/23 13:26:31
Done.
| |
| 1546 if (other is! CompoundName) return false; | |
| 1547 if (other._parts.length != _parts.length) return false; | |
| 1548 for (int i = 0; i < _parts.length; ++i) { | |
| 1549 if (other._parts[i] != _parts[i]) return false; | |
| 1550 } | |
| 1551 return true; | |
| 1552 } | |
| 1553 | |
| 1554 int get hashCode { | |
| 1555 if (_cachedHashCode < 0) { | |
| 1556 _cachedHashCode = 0; | |
| 1557 for (jsAst.Name name in _parts) { | |
| 1558 _cachedHashCode = (_cachedHashCode * 17) & 0x7fffffff; | |
| 1559 } | |
| 1560 } | |
| 1561 return _cachedHashCode; | |
| 1562 } | |
| 1563 | |
| 1564 int compareTo(other) { | |
| 1565 if (other is! _NamerName) return -1; | |
| 1566 if (other._kind != _kind) return other._kind - _kind; | |
| 1567 if (other._parts.length != _parts.length) { | |
| 1568 return other._parts.length - _parts.length; | |
| 1569 } | |
| 1570 int result = 0; | |
| 1571 for (int pos = 0; result == 0 && pos < _parts.length; pos++) { | |
| 1572 result = _parts[pos].compareTo(other._parts[pos]); | |
| 1573 } | |
| 1574 return result; | |
| 1575 } | |
| 1576 } | |
| 1577 | |
| 1369 /** | 1578 /** |
| 1370 * Generator of names for [ConstantValue] values. | 1579 * Generator of names for [ConstantValue] values. |
| 1371 * | 1580 * |
| 1372 * The names are stable under perturbations of the source. The name is either a | 1581 * The names are stable under perturbations of the source. The name is either a |
| 1373 * short sequence of words, if this can be found from the constant, or a type | 1582 * short sequence of words, if this can be found from the constant, or a type |
| 1374 * followed by a hash tag. | 1583 * followed by a hash tag. |
| 1375 * | 1584 * |
| 1376 * List_imX // A List, with hash tag. | 1585 * List_imX // A List, with hash tag. |
| 1377 * C_Sentinel // const Sentinel(), "C_" added to avoid clash | 1586 * C_Sentinel // const Sentinel(), "C_" added to avoid clash |
| 1378 * // with class name. | 1587 * // with class name. |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1543 | 1752 |
| 1544 @override | 1753 @override |
| 1545 void visitSynthetic(SyntheticConstantValue constant, [_]) { | 1754 void visitSynthetic(SyntheticConstantValue constant, [_]) { |
| 1546 switch (constant.kind) { | 1755 switch (constant.kind) { |
| 1547 case SyntheticConstantKind.DUMMY_INTERCEPTOR: | 1756 case SyntheticConstantKind.DUMMY_INTERCEPTOR: |
| 1548 add('dummy_receiver'); | 1757 add('dummy_receiver'); |
| 1549 break; | 1758 break; |
| 1550 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: | 1759 case SyntheticConstantKind.TYPEVARIABLE_REFERENCE: |
| 1551 add('type_variable_reference'); | 1760 add('type_variable_reference'); |
| 1552 break; | 1761 break; |
| 1762 case SyntheticConstantKind.NAME: | |
| 1763 add('name'); | |
| 1764 break; | |
| 1553 default: | 1765 default: |
| 1554 compiler.internalError(compiler.currentElement, | 1766 compiler.internalError(compiler.currentElement, |
| 1555 "Unexpected SyntheticConstantValue"); | 1767 "Unexpected SyntheticConstantValue"); |
| 1556 } | 1768 } |
| 1557 } | 1769 } |
| 1558 | 1770 |
| 1559 @override | 1771 @override |
| 1560 void visitDeferred(DeferredConstantValue constant, [_]) { | 1772 void visitDeferred(DeferredConstantValue constant, [_]) { |
| 1561 addRoot('Deferred'); | 1773 addRoot('Deferred'); |
| 1562 } | 1774 } |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1791 if (!first) { | 2003 if (!first) { |
| 1792 sb.write('_'); | 2004 sb.write('_'); |
| 1793 } | 2005 } |
| 1794 sb.write('_'); | 2006 sb.write('_'); |
| 1795 visit(parameter); | 2007 visit(parameter); |
| 1796 first = true; | 2008 first = true; |
| 1797 } | 2009 } |
| 1798 } | 2010 } |
| 1799 } | 2011 } |
| 1800 } | 2012 } |
| OLD | NEW |