| Index: pkg/compiler/lib/src/js_backend/namer.dart
|
| diff --git a/pkg/compiler/lib/src/js_backend/namer.dart b/pkg/compiler/lib/src/js_backend/namer.dart
|
| index 9e456cdcec5ce1c7deb3c92de6b64ebb6f9b339f..1dac9f9a201d67e57c54ecbaebf3e1bfe13c31de 100644
|
| --- a/pkg/compiler/lib/src/js_backend/namer.dart
|
| +++ b/pkg/compiler/lib/src/js_backend/namer.dart
|
| @@ -320,8 +320,10 @@ class Namer {
|
| return _jsVariableReserved;
|
| }
|
|
|
| + final String asyncPrefix = r"$async$";
|
| final String currentIsolate = r'$';
|
| final String getterPrefix = r'get$';
|
| + final String lazyGetterPrefix = r'$get$';
|
| final String setterPrefix = r'set$';
|
| final String superPrefix = r'super$';
|
| final String metadataField = '@';
|
| @@ -343,6 +345,17 @@ class Namer {
|
| /// The non-minifying namer's [callPrefix] with a dollar after it.
|
| static const String _callPrefixDollar = r'call$';
|
|
|
| + static final jsAst.Name _literalSuper = new StringBackedName("super");
|
| + static final jsAst.Name _literalDollar = new StringBackedName(r'$');
|
| + static final jsAst.Name _literalUnderscore = new StringBackedName('_');
|
| + static final jsAst.Name literalPlus = new StringBackedName('+');
|
| + static final jsAst.Name _literalDynamic = new StringBackedName("dynamic");
|
| +
|
| + jsAst.Name _literalAsyncPrefix;
|
| + jsAst.Name _literalGetterPrefix;
|
| + jsAst.Name _literalSetterPrefix;
|
| + jsAst.Name _literalLazyGetterPrefix;
|
| +
|
| // Name of property in a class description for the native dispatch metadata.
|
| final String nativeSpecProperty = '%';
|
|
|
| @@ -358,20 +371,29 @@ class Namer {
|
| /// (see [globalObjectFor]), we currently use a single namespace for all these
|
| /// names.
|
| final Set<String> usedGlobalNames = new Set<String>();
|
| - final Map<Element, String> userGlobals = <Element, String>{};
|
| - final Map<String, String> internalGlobals = <String, String>{};
|
| + final Map<Element, jsAst.Name> userGlobals =
|
| + new HashMap<Element, jsAst.Name>();
|
| + final Map<String, jsAst.Name> internalGlobals =
|
| + new HashMap<String, jsAst.Name>();
|
|
|
| /// Used disambiguated names in the instance namespace, issued by
|
| /// [_disambiguateMember], [_disambiguateInternalMember],
|
| /// [_disambiguateOperator], and [reservePublicMemberName].
|
| final Set<String> usedInstanceNames = new Set<String>();
|
| - final Map<String, String> userInstanceMembers = <String, String>{};
|
| - final Map<Element, String> internalInstanceMembers = <Element, String>{};
|
| - final Map<String, String> userInstanceOperators = <String, String>{};
|
| + final Map<String, jsAst.Name> userInstanceMembers =
|
| + new HashMap<String, jsAst.Name>();
|
| + final Map<Element, jsAst.Name> internalInstanceMembers =
|
| + new HashMap<Element, jsAst.Name>();
|
| + final Map<String, jsAst.Name> userInstanceOperators =
|
| + new HashMap<String, jsAst.Name>();
|
|
|
| final Map<String, int> popularNameCounters = <String, int>{};
|
|
|
| - final Map<ConstantValue, String> constantNames = <ConstantValue, String>{};
|
| + final Map<LibraryElement, String> libraryLongNames =
|
| + new HashMap<LibraryElement, String>();
|
| +
|
| + final Map<ConstantValue, jsAst.Name> constantNames =
|
| + new HashMap<ConstantValue, jsAst.Name>();
|
| final Map<ConstantValue, String> constantLongNames =
|
| <ConstantValue, String>{};
|
| ConstantCanonicalHasher constantHasher;
|
| @@ -391,17 +413,28 @@ class Namer {
|
| final Map<String, String> suggestedGlobalNames = <String, String>{};
|
| final Map<String, String> suggestedInstanceNames = <String, String>{};
|
|
|
| + /// Used to store unique keys for library names. Keys are not used as names,
|
| + /// nor are they visible in the output. The only serve as an internal
|
| + /// key into maps.
|
| + final Map<LibraryElement, String> _libraryKeys =
|
| + new HashMap<LibraryElement, String>();
|
| +
|
| Namer(Compiler compiler)
|
| : compiler = compiler,
|
| constantHasher = new ConstantCanonicalHasher(compiler),
|
| - functionTypeNamer = new FunctionTypeNamer(compiler);
|
| + functionTypeNamer = new FunctionTypeNamer(compiler) {
|
| + _literalAsyncPrefix = new StringBackedName(asyncPrefix);
|
| + _literalGetterPrefix = new StringBackedName(getterPrefix);
|
| + _literalSetterPrefix = new StringBackedName(setterPrefix);
|
| + _literalLazyGetterPrefix = new StringBackedName(lazyGetterPrefix);
|
| + }
|
|
|
| JavaScriptBackend get backend => compiler.backend;
|
|
|
| String get deferredTypesName => 'deferredTypes';
|
| String get isolateName => 'Isolate';
|
| String get isolatePropertiesName => r'$isolateProperties';
|
| - String get noSuchMethodName => publicInstanceMethodNameByArity(
|
| + jsAst.Name get noSuchMethodName => publicInstanceMethodNameByArity(
|
| Compiler.NO_SUCH_METHOD, Compiler.NO_SUCH_METHOD_ARG_COUNT);
|
| /**
|
| * Some closures must contain their name. The name is stored in
|
| @@ -413,57 +446,63 @@ class Namer {
|
|
|
| /// Returns the string that is to be used as the result of a call to
|
| /// [JS_GET_NAME] at [node] with argument [name].
|
| - String getNameForJsGetName(Node node, JsGetName name) {
|
| + jsAst.Name getNameForJsGetName(Node node, JsGetName name) {
|
| switch (name) {
|
| - case JsGetName.GETTER_PREFIX: return getterPrefix;
|
| - case JsGetName.SETTER_PREFIX: return setterPrefix;
|
| - case JsGetName.CALL_PREFIX: return callPrefix;
|
| - case JsGetName.CALL_PREFIX0: return '${callPrefix}\$0';
|
| - case JsGetName.CALL_PREFIX1: return '${callPrefix}\$1';
|
| - case JsGetName.CALL_PREFIX2: return '${callPrefix}\$2';
|
| - case JsGetName.CALL_PREFIX3: return '${callPrefix}\$3';
|
| - case JsGetName.CALL_CATCH_ALL: return callCatchAllName;
|
| - case JsGetName.REFLECTABLE: return reflectableField;
|
| + case JsGetName.GETTER_PREFIX: return asName(getterPrefix);
|
| + case JsGetName.SETTER_PREFIX: return asName(setterPrefix);
|
| + case JsGetName.CALL_PREFIX: return asName(callPrefix);
|
| + case JsGetName.CALL_PREFIX0: return asName('${callPrefix}\$0');
|
| + case JsGetName.CALL_PREFIX1: return asName('${callPrefix}\$1');
|
| + case JsGetName.CALL_PREFIX2: return asName('${callPrefix}\$2');
|
| + case JsGetName.CALL_PREFIX3: return asName('${callPrefix}\$3');
|
| + case JsGetName.CALL_CATCH_ALL: return asName(callCatchAllName);
|
| + case JsGetName.REFLECTABLE: return asName(reflectableField);
|
| case JsGetName.CLASS_DESCRIPTOR_PROPERTY:
|
| - return classDescriptorProperty;
|
| + return asName(classDescriptorProperty);
|
| case JsGetName.REQUIRED_PARAMETER_PROPERTY:
|
| - return requiredParameterField;
|
| - case JsGetName.DEFAULT_VALUES_PROPERTY: return defaultValuesField;
|
| - case JsGetName.CALL_NAME_PROPERTY: return callNameField;
|
| - case JsGetName.DEFERRED_ACTION_PROPERTY: return deferredAction;
|
| - case JsGetName.OPERATOR_AS_PREFIX: return operatorAsPrefix;
|
| - case JsGetName.SIGNATURE_NAME: return operatorSignature;
|
| - case JsGetName.TYPEDEF_TAG: return typedefTag;
|
| + return asName(requiredParameterField);
|
| + case JsGetName.DEFAULT_VALUES_PROPERTY: return asName(defaultValuesField);
|
| + case JsGetName.CALL_NAME_PROPERTY: return asName(callNameField);
|
| + case JsGetName.DEFERRED_ACTION_PROPERTY: return asName(deferredAction);
|
| + case JsGetName.OPERATOR_AS_PREFIX: return asName(operatorAsPrefix);
|
| + case JsGetName.SIGNATURE_NAME: return asName(operatorSignature);
|
| + case JsGetName.TYPEDEF_TAG: return asName(typedefTag);
|
| case JsGetName.FUNCTION_TYPE_VOID_RETURN_TAG:
|
| - return functionTypeVoidReturnTag;
|
| + return asName(functionTypeVoidReturnTag);
|
| case JsGetName.FUNCTION_TYPE_RETURN_TYPE_TAG:
|
| - return functionTypeReturnTypeTag;
|
| + return asName(functionTypeReturnTypeTag);
|
| case JsGetName.FUNCTION_TYPE_REQUIRED_PARAMETERS_TAG:
|
| - return functionTypeRequiredParametersTag;
|
| + return asName(functionTypeRequiredParametersTag);
|
| case JsGetName.FUNCTION_TYPE_OPTIONAL_PARAMETERS_TAG:
|
| - return functionTypeOptionalParametersTag;
|
| + return asName(functionTypeOptionalParametersTag);
|
| case JsGetName.FUNCTION_TYPE_NAMED_PARAMETERS_TAG:
|
| - return functionTypeNamedParametersTag;
|
| + return asName(functionTypeNamedParametersTag);
|
| case JsGetName.IS_INDEXABLE_FIELD_NAME:
|
| Element cls = backend.findHelper('JavaScriptIndexingBehavior');
|
| return operatorIs(cls);
|
| + case JsGetName.NULL_CLASS_TYPE_NAME:
|
| + return runtimeTypeName(compiler.nullClass);
|
| + case JsGetName.OBJECT_CLASS_TYPE_NAME:
|
| + return runtimeTypeName(compiler.objectClass);
|
| + case JsGetName.FUNCTION_CLASS_TYPE_NAME:
|
| + return runtimeTypeName(compiler.functionClass);
|
| default:
|
| compiler.reportError(
|
| node, MessageKind.GENERIC,
|
| {'text': 'Error: Namer has no name for "$name".'});
|
| - return 'BROKEN';
|
| + return asName('BROKEN');
|
| }
|
| }
|
|
|
| /// Disambiguated name for [constant].
|
| ///
|
| /// Unique within the global-member namespace.
|
| - String constantName(ConstantValue constant) {
|
| + jsAst.Name constantName(ConstantValue constant) {
|
| // In the current implementation it doesn't make sense to give names to
|
| // function constants since the function-implementation itself serves as
|
| // constant and can be accessed directly.
|
| assert(!constant.isFunction);
|
| - String result = constantNames[constant];
|
| + jsAst.Name result = constantNames[constant];
|
| if (result == null) {
|
| String longName = constantLongName(constant);
|
| result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames);
|
| @@ -530,9 +569,10 @@ class Namer {
|
| // Make sure to return a private name that starts with _ so it
|
| // cannot clash with any public names.
|
| // The name is still not guaranteed to be unique, since both the library
|
| - // name and originalName could contain $ symbols.
|
| - String libraryName = _disambiguateGlobal(library);
|
| - return '_$libraryName\$${text}';
|
| + // name and originalName could contain $ symbols and as the library
|
| + // name itself might clash.
|
| + String libraryName = _proposeNameForGlobal(library);
|
| + return "_$libraryName\$$text";
|
| }
|
| }
|
|
|
| @@ -546,7 +586,7 @@ class Namer {
|
| }
|
|
|
| /// Annotated name for [method] encoding arity and named parameters.
|
| - String instanceMethodName(FunctionElement method) {
|
| + jsAst.Name instanceMethodName(FunctionElement method) {
|
| if (method.isGenerativeConstructorBody) {
|
| return _disambiguateInternalMember(method,
|
| () => _proposeNameForConstructorBody(method));
|
| @@ -556,7 +596,8 @@ class Namer {
|
|
|
| /// Annotated name for a public method with the given [originalName]
|
| /// and [arity] and no named parameters.
|
| - String publicInstanceMethodNameByArity(String originalName, int arity) {
|
| + jsAst.Name publicInstanceMethodNameByArity(String originalName,
|
| + int arity) {
|
| return invocationName(new Selector.call(originalName, null, arity));
|
| }
|
|
|
| @@ -567,9 +608,9 @@ class Namer {
|
| ///
|
| /// This name cannot be minified because it is generated by string
|
| /// concatenation at runtime, by applyFunction in js_helper.dart.
|
| - String deriveCallMethodName(List<String> suffix) {
|
| + jsAst.Name deriveCallMethodName(List<String> suffix) {
|
| // TODO(asgerf): Avoid clashes when named parameters contain $ symbols.
|
| - return '$callPrefix\$${suffix.join(r'$')}';
|
| + return new StringBackedName('$callPrefix\$${suffix.join(r'$')}');
|
| }
|
|
|
| /// The suffix list for the pattern:
|
| @@ -601,20 +642,23 @@ class Namer {
|
| }
|
|
|
| /// Annotated name for the member being invoked by [selector].
|
| - String invocationName(Selector selector) {
|
| + jsAst.Name invocationName(Selector selector) {
|
| switch (selector.kind) {
|
| case SelectorKind.GETTER:
|
| - String disambiguatedName = _disambiguateMember(selector.memberName);
|
| + jsAst.Name disambiguatedName =
|
| + _disambiguateMember(selector.memberName);
|
| return deriveGetterName(disambiguatedName);
|
|
|
| case SelectorKind.SETTER:
|
| - String disambiguatedName = _disambiguateMember(selector.memberName);
|
| + jsAst.Name disambiguatedName =
|
| + _disambiguateMember(selector.memberName);
|
| return deriveSetterName(disambiguatedName);
|
|
|
| case SelectorKind.OPERATOR:
|
| case SelectorKind.INDEX:
|
| String operatorIdentifier = operatorNameToIdentifier(selector.name);
|
| - String disambiguatedName = _disambiguateOperator(operatorIdentifier);
|
| + jsAst.Name disambiguatedName =
|
| + _disambiguateOperator(operatorIdentifier);
|
| return disambiguatedName; // Operators are not annotated.
|
|
|
| case SelectorKind.CALL:
|
| @@ -623,7 +667,7 @@ class Namer {
|
| // Derive the annotated name for this variant of 'call'.
|
| return deriveCallMethodName(suffix);
|
| }
|
| - String disambiguatedName =
|
| + jsAst.Name disambiguatedName =
|
| _disambiguateMember(selector.memberName, suffix);
|
| return disambiguatedName; // Methods other than call are not annotated.
|
|
|
| @@ -637,14 +681,14 @@ class Namer {
|
| /**
|
| * Returns the internal name used for an invocation mirror of this selector.
|
| */
|
| - String invocationMirrorInternalName(Selector selector)
|
| + jsAst.Name invocationMirrorInternalName(Selector selector)
|
| => invocationName(selector);
|
|
|
| /**
|
| * Returns the disambiguated name for the given field, used for constructing
|
| * the getter and setter names.
|
| */
|
| - String fieldAccessorName(FieldElement element) {
|
| + jsAst.Name fieldAccessorName(FieldElement element) {
|
| return element.isInstanceMember
|
| ? _disambiguateMember(element.memberName)
|
| : _disambiguateGlobal(element);
|
| @@ -654,7 +698,7 @@ class Namer {
|
| * Returns name of the JavaScript property used to store a static or instance
|
| * field.
|
| */
|
| - String fieldPropertyName(FieldElement element) {
|
| + jsAst.Name fieldPropertyName(FieldElement element) {
|
| return element.isInstanceMember
|
| ? instanceFieldPropertyName(element)
|
| : _disambiguateGlobal(element);
|
| @@ -664,7 +708,7 @@ class Namer {
|
| * Returns name of the JavaScript property used to store the
|
| * `readTypeVariable` function for the given type variable.
|
| */
|
| - String nameForReadTypeVariable(TypeVariableElement element) {
|
| + jsAst.Name nameForReadTypeVariable(TypeVariableElement element) {
|
| return _disambiguateInternalMember(element, () => element.name);
|
| }
|
|
|
| @@ -675,14 +719,14 @@ class Namer {
|
| * Should be used together with [globalObjectFor], which denotes the object
|
| * on which the returned property name should be used.
|
| */
|
| - String globalPropertyName(Element element) {
|
| + jsAst.Name globalPropertyName(Element element) {
|
| return _disambiguateGlobal(element);
|
| }
|
|
|
| /**
|
| * Returns the JavaScript property name used to store an instance field.
|
| */
|
| - String instanceFieldPropertyName(FieldElement element) {
|
| + jsAst.Name instanceFieldPropertyName(FieldElement element) {
|
| ClassElement enclosingClass = element.enclosingClass;
|
|
|
| if (element.hasFixedBackendName) {
|
| @@ -691,7 +735,7 @@ class Namer {
|
| assert(enclosingClass.isNative &&
|
| !element.fixedBackendName.contains(r'$'));
|
|
|
| - return element.fixedBackendName;
|
| + return new StringBackedName(element.fixedBackendName);
|
| }
|
|
|
| // Instances of BoxFieldElement are special. They are already created with
|
| @@ -701,7 +745,7 @@ class Namer {
|
| // fixedBackendName, as we want to allow other namers to do something more
|
| // clever with them.
|
| if (element is BoxFieldElement) {
|
| - return element.name;
|
| + return new StringBackedName(element.name);
|
| }
|
|
|
| // If the name of the field might clash with another field,
|
| @@ -736,46 +780,46 @@ class Namer {
|
| }
|
|
|
| /// Annotated name for the setter of [element].
|
| - String setterForElement(MemberElement element) {
|
| + jsAst.Name setterForElement(MemberElement element) {
|
| // We dynamically create setters from the field-name. The setter name must
|
| // therefore be derived from the instance field-name.
|
| - String name = _disambiguateMember(element.memberName);
|
| + jsAst.Name name = _disambiguateMember(element.memberName);
|
| return deriveSetterName(name);
|
| }
|
|
|
| /// Annotated name for the setter of any member with [disambiguatedName].
|
| - String deriveSetterName(String disambiguatedName) {
|
| + jsAst.Name deriveSetterName(jsAst.Name disambiguatedName) {
|
| // We dynamically create setters from the field-name. The setter name must
|
| // therefore be derived from the instance field-name.
|
| - return '$setterPrefix$disambiguatedName';
|
| + return new SetterName(_literalSetterPrefix, disambiguatedName);
|
| }
|
|
|
| /// Annotated name for the setter of any member with [disambiguatedName].
|
| - String deriveGetterName(String disambiguatedName) {
|
| + jsAst.Name deriveGetterName(jsAst.Name disambiguatedName) {
|
| // We dynamically create getters from the field-name. The getter name must
|
| // therefore be derived from the instance field-name.
|
| - return '$getterPrefix$disambiguatedName';
|
| + return new GetterName(_literalGetterPrefix, disambiguatedName);
|
| }
|
|
|
| /// Annotated name for the getter of [element].
|
| - String getterForElement(MemberElement element) {
|
| + jsAst.Name getterForElement(MemberElement element) {
|
| // We dynamically create getters from the field-name. The getter name must
|
| // therefore be derived from the instance field-name.
|
| - String name = _disambiguateMember(element.memberName);
|
| + jsAst.Name name = _disambiguateMember(element.memberName);
|
| return deriveGetterName(name);
|
| }
|
|
|
| /// Property name for the getter of an instance member with [originalName].
|
| - String getterForMember(Name originalName) {
|
| - String disambiguatedName = _disambiguateMember(originalName);
|
| + jsAst.Name getterForMember(Name originalName) {
|
| + jsAst.Name disambiguatedName = _disambiguateMember(originalName);
|
| return deriveGetterName(disambiguatedName);
|
| }
|
|
|
| /// Disambiguated name for a compiler-owned global variable.
|
| ///
|
| /// The resulting name is unique within the global-member namespace.
|
| - String _disambiguateInternalGlobal(String name) {
|
| - String newName = internalGlobals[name];
|
| + jsAst.Name _disambiguateInternalGlobal(String name) {
|
| + jsAst.Name newName = internalGlobals[name];
|
| if (newName == null) {
|
| newName = getFreshName(name, usedGlobalNames, suggestedGlobalNames);
|
| internalGlobals[name] = newName;
|
| @@ -794,19 +838,34 @@ class Namer {
|
| /// This provides an easy mechanism of avoiding a name-clash with user-space
|
| /// globals, although the callers of must still take care not to accidentally
|
| /// pass in the same [name] for two different internal globals.
|
| - String internalGlobal(String name) {
|
| + jsAst.Name internalGlobal(String name) {
|
| assert(!name.contains(r'$'));
|
| return _disambiguateInternalGlobal(name);
|
| }
|
|
|
| + /// Generates a unique key for [library].
|
| + ///
|
| + /// Keys are meant to be used in maps and should not be visible in the output.
|
| + String _generateLibraryKey(LibraryElement library) {
|
| + return _libraryKeys.putIfAbsent(library, () {
|
| + String keyBase = library.name;
|
| + int counter = 0;
|
| + String key = keyBase;
|
| + while (_libraryKeys.values.contains(key)) {
|
| + key ="$keyBase${counter++}";
|
| + }
|
| + return key;
|
| + });
|
| + }
|
| +
|
| /// Returns the disambiguated name for a top-level or static element.
|
| ///
|
| /// The resulting name is unique within the global-member namespace.
|
| - String _disambiguateGlobal(Element element) {
|
| + jsAst.Name _disambiguateGlobal(Element element) {
|
| // TODO(asgerf): We can reuse more short names if we disambiguate with
|
| // a separate namespace for each of the global holder objects.
|
| element = element.declaration;
|
| - String newName = userGlobals[element];
|
| + jsAst.Name newName = userGlobals[element];
|
| if (newName == null) {
|
| String proposedName = _proposeNameForGlobal(element);
|
| newName = getFreshName(proposedName, usedGlobalNames,
|
| @@ -832,17 +891,17 @@ class Namer {
|
| /// The resulting name, and its associated annotated names, are unique
|
| /// to the ([originalName], [suffixes]) pair within the instance-member
|
| /// namespace.
|
| - String _disambiguateMember(Name originalName,
|
| - [List<String> suffixes = const []]) {
|
| + jsAst.Name _disambiguateMember(Name originalName,
|
| + [List<String> suffixes = const []]) {
|
| // Build a string encoding the library name, if the name is private.
|
| String libraryKey = originalName.isPrivate
|
| - ? _disambiguateGlobal(originalName.library)
|
| + ? _generateLibraryKey(originalName.library)
|
| : '';
|
|
|
| // In the unique key, separate the name parts by '@'.
|
| // This avoids clashes since the original names cannot contain that symbol.
|
| String key = '$libraryKey@${originalName.text}@${suffixes.join('@')}';
|
| - String newName = userInstanceMembers[key];
|
| + jsAst.Name newName = userInstanceMembers[key];
|
| if (newName == null) {
|
| String proposedName = privateName(originalName);
|
| if (!suffixes.isEmpty) {
|
| @@ -874,7 +933,7 @@ class Namer {
|
| String key = '$libraryPrefix@$originalName@$suffix';
|
| assert(!userInstanceMembers.containsKey(key));
|
| assert(!usedInstanceNames.contains(disambiguatedName));
|
| - userInstanceMembers[key] = disambiguatedName;
|
| + userInstanceMembers[key] = new StringBackedName(disambiguatedName);
|
| usedInstanceNames.add(disambiguatedName);
|
| }
|
|
|
| @@ -884,8 +943,9 @@ class Namer {
|
| /// constructor bodies, and super-accessors.
|
| ///
|
| /// The resulting name is unique within the instance-member namespace.
|
| - String _disambiguateInternalMember(Element element, String proposeName()) {
|
| - String newName = internalInstanceMembers[element];
|
| + jsAst.Name _disambiguateInternalMember(Element element,
|
| + String proposeName()) {
|
| + jsAst.Name newName = internalInstanceMembers[element];
|
| if (newName == null) {
|
| String name = proposeName();
|
| bool mayClashNative = _isUserClassExtendingNative(element.enclosingClass);
|
| @@ -904,8 +964,8 @@ class Namer {
|
| /// `$add` and not `+`.
|
| ///
|
| /// The resulting name is unique within the instance-member namespace.
|
| - String _disambiguateOperator(String operatorIdentifier) {
|
| - String newName = userInstanceOperators[operatorIdentifier];
|
| + jsAst.Name _disambiguateOperator(String operatorIdentifier) {
|
| + jsAst.Name newName = userInstanceOperators[operatorIdentifier];
|
| if (newName == null) {
|
| newName = getFreshName(operatorIdentifier, usedInstanceNames,
|
| suggestedInstanceNames);
|
| @@ -926,11 +986,11 @@ class Namer {
|
| ///
|
| /// Note that [MinifyNamer] overrides this method with one that produces
|
| /// minified names.
|
| - String getFreshName(String proposedName,
|
| - Set<String> usedNames,
|
| - Map<String, String> suggestedNames,
|
| - {bool sanitizeForAnnotations: false,
|
| - bool sanitizeForNatives: false}) {
|
| + jsAst.Name getFreshName(String proposedName,
|
| + Set<String> usedNames,
|
| + Map<String, String> suggestedNames,
|
| + {bool sanitizeForAnnotations: false,
|
| + bool sanitizeForNatives: false}) {
|
| if (sanitizeForAnnotations) {
|
| proposedName = _sanitizeForAnnotations(proposedName);
|
| }
|
| @@ -951,7 +1011,7 @@ class Namer {
|
| candidate = "$proposedName$i";
|
| }
|
| usedNames.add(candidate);
|
| - return candidate;
|
| + return new StringBackedName(candidate);
|
| }
|
|
|
| /// Returns a variant of [name] that cannot clash with the annotated
|
| @@ -1017,6 +1077,8 @@ class Namer {
|
| }
|
| } else if (element.isLibrary) {
|
| LibraryElement library = element;
|
| + name = libraryLongNames[library];
|
| + if (name != null) return name;
|
| name = library.getLibraryOrScriptName();
|
| if (name.contains('.')) {
|
| // For libraries that have a library tag, we use the last part
|
| @@ -1035,6 +1097,15 @@ class Namer {
|
| name = 'lib_$name';
|
| }
|
| }
|
| + // Names constructed based on a libary name will be further disambiguated.
|
| + // However, as names from the same libary should have the same libary
|
| + // name part, we disambiguate the library name here.
|
| + String disambiguated = name;
|
| + for (int c = 0; libraryLongNames.containsValue(disambiguated); c++) {
|
| + disambiguated = "$name$c";
|
| + }
|
| + libraryLongNames[library] = disambiguated;
|
| + name = disambiguated;
|
| } else {
|
| name = element.name;
|
| }
|
| @@ -1069,7 +1140,7 @@ class Namer {
|
| }
|
|
|
| /// Property name used for `getInterceptor` or one of its specializations.
|
| - String nameForGetInterceptor(Iterable<ClassElement> classes) {
|
| + jsAst.Name nameForGetInterceptor(Iterable<ClassElement> classes) {
|
| FunctionElement getInterceptor = backend.getInterceptorMethod;
|
| if (classes.contains(backend.jsInterceptorClass)) {
|
| // If the base Interceptor class is in the set of intercepted classes, we
|
| @@ -1086,27 +1157,24 @@ class Namer {
|
|
|
| /// Property name used for the one-shot interceptor method for the given
|
| /// [selector] and return-type specialization.
|
| - String nameForGetOneShotInterceptor(Selector selector,
|
| - Iterable<ClassElement> classes) {
|
| + jsAst.Name nameForGetOneShotInterceptor(Selector selector,
|
| + Iterable<ClassElement> classes) {
|
| // The one-shot name is a global name derived from the invocation name. To
|
| // avoid instability we would like the names to be unique and not clash with
|
| // other global names.
|
| -
|
| - String root = invocationName(selector);
|
| + jsAst.Name root = invocationName(selector);
|
|
|
| if (classes.contains(backend.jsInterceptorClass)) {
|
| // If the base Interceptor class is in the set of intercepted classes,
|
| // this is the most general specialization which uses the generic
|
| - // getInterceptor method. To keep the name short, we add '$' only to
|
| - // distinguish from internal globals requested from outside the Namer
|
| - // with internalGlobal().
|
| + // getInterceptor method.
|
| // TODO(sra): Find a way to get the simple name when Object is not in the
|
| // set of classes for most general variant, e.g. "$lt$n" could be "$lt".
|
| - if (selector.isGetter || selector.isSetter) root = '$root\$';
|
| - return _disambiguateInternalGlobal(root);
|
| + return new CompoundName([root, _literalDollar]);
|
| } else {
|
| String suffix = suffixForGetInterceptor(classes);
|
| - return _disambiguateInternalGlobal("$root\$$suffix");
|
| + return new CompoundName([root, _literalDollar,
|
| + new StringBackedName(suffix)]);
|
| }
|
| }
|
|
|
| @@ -1119,8 +1187,8 @@ class Namer {
|
| /// [operatorIsPrefix] or [operatorAsPrefix]. If this is a function type,
|
| /// then by convention, an underscore must also separate [operatorIsPrefix]
|
| /// from the type name.
|
| - String runtimeTypeName(TypeDeclarationElement element) {
|
| - if (element == null) return 'dynamic';
|
| + jsAst.Name runtimeTypeName(TypeDeclarationElement element) {
|
| + if (element == null) return _literalDynamic;
|
| // The returned name affects both the global and instance member namespaces:
|
| //
|
| // - If given a class, this must coincide with the class name, which
|
| @@ -1139,7 +1207,7 @@ class Namer {
|
| ///
|
| /// This is both the *runtime type* of the class (see [runtimeTypeName])
|
| /// and a global property name in which to store its JS constructor.
|
| - String className(ClassElement class_) => _disambiguateGlobal(class_);
|
| + jsAst.Name className(ClassElement class_) => _disambiguateGlobal(class_);
|
|
|
| /// Property name on which [member] can be accessed directly,
|
| /// without clashing with another JS property name.
|
| @@ -1161,11 +1229,12 @@ class Namer {
|
| /// this.super$A$foo(); // super.foo()
|
| /// }
|
| ///
|
| - String aliasedSuperMemberPropertyName(Element member) {
|
| + jsAst.Name aliasedSuperMemberPropertyName(Element member) {
|
| assert(!member.isField); // Fields do not need super aliases.
|
| - String methodName = instanceMethodName(member);
|
| - return _disambiguateInternalMember(member,
|
| - () => 'super\$${member.enclosingClass.name}\$$methodName');
|
| + return _disambiguateInternalMember(member, () {
|
| + String invocationName = operatorNameToIdentifier(member.name);
|
| + return "super\$${member.enclosingClass.name}\$$invocationName";
|
| + });
|
| }
|
|
|
| /// Property name in which to store the given static or instance [method].
|
| @@ -1174,7 +1243,7 @@ class Namer {
|
| ///
|
| /// The name is not necessarily unique to [method], since a static method
|
| /// may share its name with an instance method.
|
| - String methodPropertyName(Element method) {
|
| + jsAst.Name methodPropertyName(Element method) {
|
| return method.isInstanceMember
|
| ? instanceMethodName(method)
|
| : globalPropertyName(method);
|
| @@ -1213,23 +1282,33 @@ class Namer {
|
| library.getLibraryOrScriptName().hashCode % userGlobalObjects.length];
|
| }
|
|
|
| - String lazyInitializerName(Element element) {
|
| + jsAst.Name deriveLazyInitializerName(jsAst.Name name) {
|
| + // These are not real dart getters, so do not use GetterName;
|
| + return new CompoundName([_literalLazyGetterPrefix, name]);
|
| + }
|
| +
|
| + jsAst.Name lazyInitializerName(Element element) {
|
| assert(Elements.isStaticOrTopLevelField(element));
|
| - String name = _disambiguateGlobal(element);
|
| - return _disambiguateInternalGlobal("$getterPrefix$name");
|
| + jsAst.Name name = _disambiguateGlobal(element);
|
| + // These are not real dart getters, so do not use GetterName;
|
| + return deriveLazyInitializerName(name);
|
| }
|
|
|
| - String staticClosureName(Element element) {
|
| + jsAst.Name staticClosureName(Element element) {
|
| assert(Elements.isStaticOrTopLevelFunction(element));
|
| - String name = _disambiguateGlobal(element);
|
| - return _disambiguateInternalGlobal("$name\$closure");
|
| + String enclosing = element.enclosingClass == null
|
| + ? "" : element.enclosingClass.name;
|
| + String library = _proposeNameForGlobal(element.library);
|
| + return _disambiguateInternalGlobal(
|
| + "${library}_${enclosing}_${element.name}\$closure");
|
| }
|
|
|
| // This name is used as part of the name of a TypeConstant
|
| String uniqueNameForTypeConstantElement(Element element) {
|
| // TODO(sra): If we replace the period with an identifier character,
|
| // TypeConstants will have better names in unminified code.
|
| - return "${globalObjectFor(element)}.${globalPropertyName(element)}";
|
| + String library = _proposeNameForGlobal(element.library);
|
| + return "${library}.${element.name}";
|
| }
|
|
|
| String globalObjectForConstant(ConstantValue constant) => 'C';
|
| @@ -1254,30 +1333,32 @@ class Namer {
|
|
|
| String get functionTypeNamedParametersTag => r'named';
|
|
|
| - Map<FunctionType,String> functionTypeNameMap =
|
| - new Map<FunctionType,String>();
|
| + Map<FunctionType, jsAst.Name> functionTypeNameMap =
|
| + new HashMap<FunctionType, jsAst.Name>();
|
| final FunctionTypeNamer functionTypeNamer;
|
|
|
| - String getFunctionTypeName(FunctionType functionType) {
|
| + jsAst.Name getFunctionTypeName(FunctionType functionType) {
|
| return functionTypeNameMap.putIfAbsent(functionType, () {
|
| String proposedName = functionTypeNamer.computeName(functionType);
|
| - String freshName = getFreshName(proposedName, usedInstanceNames,
|
| - suggestedInstanceNames);
|
| - return freshName;
|
| + return getFreshName(proposedName, usedInstanceNames,
|
| + suggestedInstanceNames);
|
| });
|
| }
|
|
|
| - String operatorIsType(DartType type) {
|
| + jsAst.Name operatorIsType(DartType type) {
|
| if (type.isFunctionType) {
|
| // TODO(erikcorry): Reduce from $isx to ix when we are minifying.
|
| - return '${operatorIsPrefix}_${getFunctionTypeName(type)}';
|
| + return new CompoundName([new StringBackedName(operatorIsPrefix),
|
| + _literalUnderscore,
|
| + getFunctionTypeName(type)]);
|
| }
|
| return operatorIs(type.element);
|
| }
|
|
|
| - String operatorIs(ClassElement element) {
|
| + jsAst.Name operatorIs(ClassElement element) {
|
| // TODO(erikcorry): Reduce from $isx to ix when we are minifying.
|
| - return '${operatorIsPrefix}${runtimeTypeName(element)}';
|
| + return new CompoundName([new StringBackedName(operatorIsPrefix),
|
| + runtimeTypeName(element)]);
|
| }
|
|
|
| /// Returns a name that does not clash with reserved JS keywords.
|
| @@ -1289,8 +1370,29 @@ class Namer {
|
| return name;
|
| }
|
|
|
| - String substitutionName(Element element) {
|
| - return '${operatorAsPrefix}${runtimeTypeName(element)}';
|
| + jsAst.Name substitutionName(Element element) {
|
| + return new CompoundName([new StringBackedName(operatorAsPrefix),
|
| + runtimeTypeName(element)]);
|
| + }
|
| +
|
| + /// Translates a [String] into the corresponding [Name] data structure as
|
| + /// used by the namer.
|
| + ///
|
| + /// If [name] is a setter or getter name, the corresponding [GetterName] or
|
| + /// [SetterName] data structure is used.
|
| + jsAst.Name asName(String name) {
|
| + if (name.startsWith(getterPrefix) && name.length > getterPrefix.length) {
|
| + return new GetterName(_literalGetterPrefix,
|
| + new StringBackedName(
|
| + name.substring(getterPrefix.length)));
|
| + }
|
| + if (name.startsWith(setterPrefix) && name.length > setterPrefix.length) {
|
| + return new GetterName(_literalSetterPrefix,
|
| + new StringBackedName(
|
| + name.substring(setterPrefix.length)));
|
| + }
|
| +
|
| + return new StringBackedName(name);
|
| }
|
|
|
| /// Returns a variable name that cannot clash with a keyword, a global
|
| @@ -1305,6 +1407,20 @@ class Namer {
|
| return name;
|
| }
|
|
|
| + /// Returns a safe variable name for use in async rewriting.
|
| + ///
|
| + /// Has the same property as [safeVariableName] but does not clash with
|
| + /// names returned from there.
|
| + /// Additionally, when used as a prefix to a variable name, the result
|
| + /// will be safe to use, as well.
|
| + String safeVariablePrefixForAsyncRewrite(String name) {
|
| + return "$asyncPrefix$name";
|
| + }
|
| +
|
| + jsAst.Name deriveAsyncBodyName(jsAst.Name original) {
|
| + return new _AsyncName(_literalAsyncPrefix, original);
|
| + }
|
| +
|
| String operatorNameToIdentifier(String name) {
|
| if (name == null) return null;
|
| if (name == '==') {
|
| @@ -1359,13 +1475,140 @@ class Namer {
|
| }
|
|
|
| void forgetElement(Element element) {
|
| - String globalName = userGlobals[element];
|
| + jsAst.Name globalName = userGlobals[element];
|
| invariant(element, globalName != null, message: 'No global name.');
|
| usedGlobalNames.remove(globalName);
|
| userGlobals.remove(element);
|
| }
|
| }
|
|
|
| +abstract class _NamerName extends jsAst.Name {
|
| + int get _kind;
|
| +}
|
| +
|
| +class StringBackedName extends _NamerName {
|
| + final String name;
|
| + int get _kind => 1;
|
| +
|
| + StringBackedName(this.name);
|
| +
|
| + toString() => throw new UnsupportedError("Cannot convert a name to a string");
|
| +
|
| + operator==(other) {
|
| + if (identical(this, other)) return true;
|
| + return (other is StringBackedName) && other.name == name;
|
| + }
|
| +
|
| + int get hashCode => name.hashCode;
|
| +
|
| + int compareTo(_NamerName other) {
|
| + if (other._kind != _kind) return other._kind - _kind;
|
| + return name.compareTo(other.name);
|
| + }
|
| +}
|
| +
|
| +abstract class _PrefixedName extends _NamerName {
|
| + final jsAst.Name prefix;
|
| + final jsAst.Name base;
|
| + int get _kind;
|
| +
|
| + _PrefixedName(this.prefix, this.base);
|
| +
|
| + String get name => prefix.name + base.name;
|
| +
|
| + toString() => throw new UnsupportedError("Cannot convert a name to a string");
|
| +
|
| + bool operator==(other) {
|
| + if (identical(this, other)) return true;
|
| + if (other is! _PrefixedName) return false;
|
| + return other.base == base && other.prefix == prefix;
|
| + }
|
| +
|
| + int get hashCode => base.hashCode * 13 + prefix.hashCode;
|
| +
|
| + int compareTo(_NamerName other) {
|
| + if (other._kind != _kind) return other._kind - _kind;
|
| + _PrefixedName otherSameKind = other;
|
| + int result = prefix.compareTo(otherSameKind.prefix);
|
| + if (result == 0) {
|
| + result = name.compareTo(otherSameKind.name);
|
| + }
|
| + return result;
|
| + }
|
| +}
|
| +
|
| +class GetterName extends _PrefixedName {
|
| + int get _kind => 2;
|
| +
|
| + GetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
|
| +}
|
| +
|
| +class SetterName extends _PrefixedName {
|
| + int get _kind => 3;
|
| +
|
| + SetterName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
|
| +}
|
| +
|
| +class _AsyncName extends _PrefixedName {
|
| + int get _kind => 4;
|
| +
|
| + _AsyncName(jsAst.Name prefix, jsAst.Name base) : super(prefix, base);
|
| +
|
| + @override
|
| + bool get allowRename => true;
|
| +}
|
| +
|
| +class CompoundName extends _NamerName {
|
| + final List<_NamerName> _parts;
|
| + int get _kind => 4;
|
| + String _cachedName;
|
| + int _cachedHashCode = -1;
|
| +
|
| + CompoundName(this._parts);
|
| +
|
| + String get name {
|
| + if (_cachedName == null) {
|
| + _cachedName = _parts.map((jsAst.Name name) => name.name).join();
|
| + }
|
| + return _cachedName;
|
| + }
|
| +
|
| + toString() => throw new UnsupportedError("Cannot convert a name to a string");
|
| +
|
| + bool operator==(other) {
|
| + if (identical(this, other)) return true;
|
| + if (other is! CompoundName) return false;
|
| + if (other._parts.length != _parts.length) return false;
|
| + for (int i = 0; i < _parts.length; ++i) {
|
| + if (other._parts[i] != _parts[i]) return false;
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + int get hashCode {
|
| + if (_cachedHashCode < 0) {
|
| + _cachedHashCode = 0;
|
| + for (jsAst.Name name in _parts) {
|
| + _cachedHashCode = (_cachedHashCode * 17 + name.hashCode) & 0x7fffffff;
|
| + }
|
| + }
|
| + return _cachedHashCode;
|
| + }
|
| +
|
| + int compareTo(_NamerName other) {
|
| + if (other._kind != _kind) return other._kind - _kind;
|
| + CompoundName otherSameKind = other;
|
| + if (otherSameKind._parts.length != _parts.length) {
|
| + return otherSameKind._parts.length - _parts.length;
|
| + }
|
| + int result = 0;
|
| + for (int pos = 0; result == 0 && pos < _parts.length; pos++) {
|
| + result = _parts[pos].compareTo(otherSameKind._parts[pos]);
|
| + }
|
| + return result;
|
| + }
|
| +}
|
| +
|
| /**
|
| * Generator of names for [ConstantValue] values.
|
| *
|
| @@ -1550,6 +1793,9 @@ class ConstantNamingVisitor implements ConstantValueVisitor {
|
| case SyntheticConstantKind.TYPEVARIABLE_REFERENCE:
|
| add('type_variable_reference');
|
| break;
|
| + case SyntheticConstantKind.NAME:
|
| + add('name');
|
| + break;
|
| default:
|
| compiler.internalError(compiler.currentElement,
|
| "Unexpected SyntheticConstantValue");
|
|
|