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

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

Issue 1198293002: dart2js: Use an abstract Name class for names in the generated JavaScript ast. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Comments Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of js_backend; 5 part of js_backend;
6 6
7 /** 7 /**
8 * Assigns JavaScript identifiers to Dart variables, class-names and members. 8 * Assigns JavaScript identifiers to Dart variables, class-names and members.
9 * 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
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
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
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
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
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
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
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
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
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
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698