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

Unified 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: fix tests 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 side-by-side diff with in-line comments
Download patch
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");

Powered by Google App Engine
This is Rietveld 408576698