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 |