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