| Index: sdk/lib/_internal/compiler/implementation/js_backend/namer.dart | 
| diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart | 
| index c4888b24b616c74b3b8c6622b1573bead56fc366..420ba8296d22503db320f7c0f1cb08b741d4a2af 100644 | 
| --- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart | 
| +++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart | 
| @@ -8,8 +8,6 @@ part of js_backend; | 
| * Assigns JavaScript identifiers to Dart variables, class-names and members. | 
| */ | 
| class Namer { | 
| -  final Compiler compiler; | 
| - | 
| static Set<String> _jsReserved = null; | 
| Set<String> get jsReserved { | 
| if (_jsReserved == null) { | 
| @@ -20,15 +18,22 @@ class Namer { | 
| return _jsReserved; | 
| } | 
|  | 
| +  final String CURRENT_ISOLATE = r'$'; | 
| + | 
| /** | 
| * Map from top-level or static elements to their unique identifiers provided | 
| * by [getName]. | 
| * | 
| * Invariant: Keys must be declaration elements. | 
| */ | 
| +  final Compiler compiler; | 
| final Map<Element, String> globals; | 
| -  final Map<String, int> usedGlobals; | 
| final Map<String, LibraryElement> shortPrivateNameOwners; | 
| +  final Set<String> usedGlobalNames; | 
| +  final Set<String> usedInstanceNames; | 
| +  final Map<String, String> instanceNameMap; | 
| +  final Map<String, String> globalNameMap; | 
| +  final Map<String, int> popularNameCounters; | 
|  | 
| /** | 
| * A cache of names used for bailout methods. We make sure two | 
| @@ -45,22 +50,27 @@ class Namer { | 
|  | 
| Namer(this.compiler) | 
| : globals = new Map<Element, String>(), | 
| -        usedGlobals = new Map<String, int>(), | 
| shortPrivateNameOwners = new Map<String, LibraryElement>(), | 
| bailoutNames = new Map<Element, String>(), | 
| usedBailoutInstanceNames = new Set<String>(), | 
| -        constantNames = new Map<Constant, String>(); | 
| - | 
| -  final String CURRENT_ISOLATE = r'$'; | 
| -  final String ISOLATE = 'Isolate'; | 
| -  final String ISOLATE_PROPERTIES = r"$isolateProperties"; | 
| +        usedGlobalNames = new Set<String>(), | 
| +        usedInstanceNames = new Set<String>(), | 
| +        instanceNameMap = new Map<String, String>(), | 
| +        globalNameMap = new Map<String, String>(), | 
| +        constantNames = new Map<Constant, String>(), | 
| +        popularNameCounters = new Map<String, int>(); | 
| + | 
| +  String get isolateName => 'Isolate'; | 
| +  String get isolatePropertiesName => r'$isolateProperties'; | 
| /** | 
| * Some closures must contain their name. The name is stored in | 
| * [STATIC_CLOSURE_NAME_NAME]. | 
| */ | 
| -  final String STATIC_CLOSURE_NAME_NAME = r'$name'; | 
| -  static const SourceString CLOSURE_INVOCATION_NAME = | 
| -      Compiler.CALL_OPERATOR_NAME; | 
| +  String get STATIC_CLOSURE_NAME_NAME => r'$name'; | 
| +  SourceString get closureInvocationSelectorName => Compiler.CALL_OPERATOR_NAME; | 
| +  bool get shouldMinify => false; | 
| + | 
| +  bool isReserved(String name) => name == isolateName; | 
|  | 
| String constantName(Constant constant) { | 
| // In the current implementation it doesn't make sense to give names to | 
| @@ -69,15 +79,28 @@ class Namer { | 
| assert(!constant.isFunction()); | 
| String result = constantNames[constant]; | 
| if (result == null) { | 
| -      result = getFreshGlobalName("CTC"); | 
| +      String longName; | 
| +      if (shouldMinify) { | 
| +        if (constant.isString()) { | 
| +          StringConstant stringConstant = constant; | 
| +          // The minifier always constructs a new name, using the argument as | 
| +          // input to its hashing algorithm.  The given name does not need to be | 
| +          // valid. | 
| +          longName = stringConstant.value.slowToString(); | 
| +        } else { | 
| +          longName = "C"; | 
| +        } | 
| +      } else { | 
| +        longName = "CONSTANT"; | 
| +      } | 
| +      result = getFreshName(longName, usedGlobalNames); | 
| constantNames[constant] = result; | 
| } | 
| return result; | 
| } | 
|  | 
| String closureInvocationName(Selector selector) { | 
| -    // TODO(floitsch): mangle, while not conflicting with instance names. | 
| -    return instanceMethodInvocationName(null, CLOSURE_INVOCATION_NAME, | 
| +    return instanceMethodInvocationName(null, closureInvocationSelectorName, | 
| selector); | 
| } | 
|  | 
| @@ -104,25 +127,32 @@ class Namer { | 
| * mangles the [name] so that each library has a unique name. | 
| */ | 
| String privateName(LibraryElement lib, SourceString name) { | 
| +    String result; | 
| if (name.isPrivate()) { | 
| String nameString = name.slowToString(); | 
| // The first library asking for a short private name wins. | 
| -      LibraryElement owner = | 
| +      LibraryElement owner = shouldMinify ? | 
| +          lib : | 
| shortPrivateNameOwners.putIfAbsent(nameString, () => lib); | 
| // If a private name could clash with a mangled private name we don't | 
| // use the short name. For example a private name "_lib3_foo" would | 
| // clash with "_foo" from "lib3". | 
| -      if (identical(owner, lib) && !nameString.startsWith('_$LIBRARY_PREFIX')) { | 
| -        return nameString; | 
| +      if (owner == lib && | 
| +          !nameString.startsWith('_$LIBRARY_PREFIX') && | 
| +          !shouldMinify) { | 
| +        result = nameString; | 
| +      } else { | 
| +        String libName = getName(lib); | 
| +        // If a library name does not start with the [LIBRARY_PREFIX] then our | 
| +        // assumptions about clashing with mangled private members do not hold. | 
| +        assert(shouldMinify || libName.startsWith(LIBRARY_PREFIX)); | 
| +        // TODO(erikcorry): Fix this with other manglings to avoid clashes. | 
| +        result = '_lib$libName\$$nameString'; | 
| } | 
| -      String libName = getName(lib); | 
| -      // If a library name does not start with the [LIBRARY_PREFIX] then our | 
| -      // assumptions about clashing with mangled private members do not hold. | 
| -      assert(libName.startsWith(LIBRARY_PREFIX)); | 
| -      return '_$libName$nameString'; | 
| } else { | 
| -      return name.slowToString(); | 
| +      result = name.slowToString(); | 
| } | 
| +    return result; | 
| } | 
|  | 
| String instanceMethodName(FunctionElement element) { | 
| @@ -135,21 +165,27 @@ class Namer { | 
| FunctionSignature signature = element.computeSignature(compiler); | 
| String methodName = | 
| '${privateName(lib, name)}\$${signature.parameterCount}'; | 
| -    if (!signature.optionalParametersAreNamed) { | 
| -      return methodName; | 
| -    } else if (!signature.optionalParameters.isEmpty) { | 
| +    if (signature.optionalParametersAreNamed && | 
| +        !signature.optionalParameters.isEmpty) { | 
| StringBuffer buffer = new StringBuffer(); | 
| signature.orderedOptionalParameters.forEach((Element element) { | 
| buffer.add('\$${JsNames.getValid(element.name.slowToString())}'); | 
| }); | 
| -      return '$methodName$buffer'; | 
| +      methodName = '$methodName$buffer'; | 
| } | 
| +    if (name == closureInvocationSelectorName) return methodName; | 
| +    return getMappedInstanceName(methodName); | 
| } | 
|  | 
| String publicInstanceMethodNameByArity(SourceString name, int arity) { | 
| name = Elements.operatorNameToIdentifier(name); | 
| assert(!name.isPrivate()); | 
| -    return '${name.slowToString()}\$$arity'; | 
| +    var base = name.slowToString(); | 
| +    // We don't mangle the closure invoking function name because it is | 
| +    // generated in by string concatenation applyFunction from js_helper.dart. | 
| +    var proposedName = '$base\$$arity'; | 
| +    if (base == closureInvocationSelectorName) return proposedName; | 
| +    return getMappedInstanceName(proposedName); | 
| } | 
|  | 
| String instanceMethodInvocationName(LibraryElement lib, SourceString name, | 
| @@ -162,59 +198,108 @@ class Namer { | 
| buffer.add(r'$'); | 
| argumentName.printOn(buffer); | 
| } | 
| -    return '${privateName(lib, name)}\$${selector.argumentCount}$buffer'; | 
| +    if (name == closureInvocationSelectorName) { | 
| +    // We don't mangle the closure invoking function name because it is | 
| +    // generated in by string concatenation applyFunction from js_helper.dart. | 
| +      return '$closureInvocationSelectorName\$${selector.argumentCount}$buffer'; | 
| +    } | 
| +    return getMappedInstanceName( | 
| +        '${privateName(lib, name)}\$${selector.argumentCount}$buffer'); | 
| } | 
|  | 
| String instanceFieldName(LibraryElement libraryElement, SourceString name) { | 
| String proposedName = privateName(libraryElement, name); | 
| -    return safeName(proposedName); | 
| +    return getMappedInstanceName(proposedName); | 
| } | 
|  | 
| +  // Construct a new name for the element based on the library and class it is | 
| +  // in.  The name here is not important, we just need to make sure it is | 
| +  // unique.  If we are minifying, we actually construct the name from the | 
| +  // minified versions of the class and instance names, but the result is | 
| +  // minified once again, so that is not visible in the end result. | 
| String shadowedFieldName(Element fieldElement) { | 
| +    // Check for following situation: Native field ${fieldElement.name} has | 
| +    // fixed JSName ${fieldElement.nativeName()}, but a subclass shadows this | 
| +    // name.  We normally handle that by renaming the superclass field, but we | 
| +    // can't do that because native fields have fixed JSNames.  In practice | 
| +    // this can't happen because we can't inherit from native classes. | 
| +    assert (!fieldElement.isNative()); | 
| + | 
| ClassElement cls = fieldElement.getEnclosingClass(); | 
| LibraryElement libraryElement = fieldElement.getLibrary(); | 
| String libName = getName(libraryElement); | 
| String clsName = getName(cls); | 
| String instanceName = instanceFieldName(libraryElement, fieldElement.name); | 
| -    return safeName('$libName\$$clsName\$$instanceName'); | 
| +    return getMappedInstanceName('$libName\$$clsName\$$instanceName'); | 
| } | 
|  | 
| String setterName(LibraryElement lib, SourceString name) { | 
| // We dynamically create setters from the field-name. The setter name must | 
| // therefore be derived from the instance field-name. | 
| -    String fieldName = safeName(privateName(lib, name)); | 
| +    String fieldName = getMappedInstanceName(privateName(lib, name)); | 
| return 'set\$$fieldName'; | 
| } | 
|  | 
| +  String setterNameFromAccessorName(String name) { | 
| +    // We dynamically create setters from the field-name. The setter name must | 
| +    // therefore be derived from the instance field-name. | 
| +    return 'set\$$name'; | 
| +  } | 
| + | 
| String publicGetterName(SourceString name) { | 
| // We dynamically create getters from the field-name. The getter name must | 
| // therefore be derived from the instance field-name. | 
| -    String fieldName = safeName(name.slowToString()); | 
| +    String fieldName = getMappedInstanceName(name.slowToString()); | 
| return 'get\$$fieldName'; | 
| } | 
|  | 
| +  String getterNameFromAccessorName(String name) { | 
| +    // We dynamically create getters from the field-name. The getter name must | 
| +    // therefore be derived from the instance field-name. | 
| +    return 'get\$$name'; | 
| +  } | 
| + | 
| String getterName(LibraryElement lib, SourceString name) { | 
| // We dynamically create getters from the field-name. The getter name must | 
| // therefore be derived from the instance field-name. | 
| -    String fieldName = safeName(privateName(lib, name)); | 
| +    String fieldName = getMappedInstanceName(privateName(lib, name)); | 
| return 'get\$$fieldName'; | 
| } | 
|  | 
| -  String getFreshGlobalName(String proposedName) { | 
| -    String name = proposedName; | 
| -    int count = usedGlobals[name]; | 
| -    if (count != null) { | 
| -      // Not the first time we see this name. Append a number to make it unique. | 
| -      do { | 
| -        name = '$proposedName${count++}'; | 
| -      } while (usedGlobals[name] != null); | 
| -      // Record the count in case we see this name later. We | 
| -      // frequently see names multiple times, as all our closures use | 
| -      // the same name for their class. | 
| -      usedGlobals[proposedName] = count; | 
| +  String getMappedGlobalName(String proposedName) { | 
| +    var newName = globalNameMap[proposedName]; | 
| +    if (newName == null) { | 
| +      newName = getFreshName(proposedName, usedGlobalNames); | 
| +      globalNameMap[proposedName] = newName; | 
| } | 
| -    usedGlobals[name] = 0; | 
| -    return name; | 
| +    return newName; | 
| +  } | 
| + | 
| +  String getMappedInstanceName(String proposedName) { | 
| +    var newName = instanceNameMap[proposedName]; | 
| +    if (newName == null) { | 
| +      newName = getFreshName(proposedName, usedInstanceNames); | 
| +      instanceNameMap[proposedName] = newName; | 
| +    } | 
| +    return newName; | 
| +  } | 
| + | 
| +  String getFreshName(String proposedName, Set<String> usedNames) { | 
| +    var candidate; | 
| +    proposedName = safeName(proposedName); | 
| +    if (!usedNames.contains(proposedName)) { | 
| +      candidate = proposedName; | 
| +    } else { | 
| +      var counter = popularNameCounters[proposedName]; | 
| +      var i = counter == null ? 0 : counter; | 
| +      while (usedNames.contains("$proposedName$i")) { | 
| +        i++; | 
| +      } | 
| +      popularNameCounters[proposedName] = i + 1; | 
| +      candidate = "$proposedName$i"; | 
| +    } | 
| +    usedNames.add(candidate); | 
| +    return candidate; | 
| } | 
|  | 
| static const String LIBRARY_PREFIX = "lib"; | 
| @@ -247,29 +332,38 @@ class Namer { | 
| } else { | 
| name = element.name.slowToString(); | 
| } | 
| -    return safeName(name); | 
| +    return name; | 
| } | 
|  | 
| String getSpecializedName(Element element, Collection<ClassElement> classes) { | 
| +    // This gets the minified name, but it doesn't really make much difference. | 
| +    // The important thing is that it is a unique name. | 
| StringBuffer buffer = new StringBuffer('${getName(element)}\$'); | 
| for (ClassElement cls in classes) { | 
| buffer.add(getName(cls)); | 
| } | 
| -    return safeName(buffer.toString()); | 
| +    return getMappedGlobalName(buffer.toString()); | 
| } | 
|  | 
| String getBailoutName(Element element) { | 
| String name = bailoutNames[element]; | 
| if (name != null) return name; | 
| bool global = !element.isInstanceMember(); | 
| +    // Despite the name of the variable, this gets the minified name when we | 
| +    // are minifying, but it doesn't really make much difference.  The | 
| +    // important thing is that it is a unique name.  We add $bailout and, if we | 
| +    // are minifying, we minify the minified name and '$bailout'. | 
| String unminifiedName = '${getName(element)}\$bailout'; | 
| -    name = unminifiedName; | 
| -    if (!global) { | 
| +    if (global) { | 
| +      name = getMappedGlobalName(unminifiedName); | 
| +    } else { | 
| +      name = unminifiedName; | 
| int i = 0; | 
| while (usedBailoutInstanceNames.contains(name)) { | 
| name = '$unminifiedName${i++}'; | 
| } | 
| usedBailoutInstanceNames.add(name); | 
| +      name = getMappedInstanceName(name); | 
| } | 
| bailoutNames[element] = name; | 
| return name; | 
| @@ -307,21 +401,29 @@ class Namer { | 
|  | 
| String guess = _computeGuess(element); | 
| ElementKind kind = element.kind; | 
| -      if (identical(kind, ElementKind.VARIABLE) || | 
| -          identical(kind, ElementKind.PARAMETER)) { | 
| +      if (kind == ElementKind.VARIABLE || | 
| +          kind == ElementKind.PARAMETER) { | 
| // The name is not guaranteed to be unique. | 
| -        return guess; | 
| +        return safeName(guess); | 
| } | 
| -      if (identical(kind, ElementKind.GENERATIVE_CONSTRUCTOR) || | 
| -          identical(kind, ElementKind.FUNCTION) || | 
| -          identical(kind, ElementKind.CLASS) || | 
| -          identical(kind, ElementKind.FIELD) || | 
| -          identical(kind, ElementKind.GETTER) || | 
| -          identical(kind, ElementKind.SETTER) || | 
| -          identical(kind, ElementKind.TYPEDEF) || | 
| -          identical(kind, ElementKind.LIBRARY) || | 
| -          identical(kind, ElementKind.MALFORMED_TYPE)) { | 
| -        String result = getFreshGlobalName(guess); | 
| +      if (kind == ElementKind.GENERATIVE_CONSTRUCTOR || | 
| +          kind == ElementKind.FUNCTION || | 
| +          kind == ElementKind.CLASS || | 
| +          kind == ElementKind.FIELD || | 
| +          kind == ElementKind.GETTER || | 
| +          kind == ElementKind.SETTER || | 
| +          kind == ElementKind.TYPEDEF || | 
| +          kind == ElementKind.LIBRARY || | 
| +          kind == ElementKind.MALFORMED_TYPE) { | 
| +        bool isNative = false; | 
| +        if (kind == ElementKind.CLASS) { | 
| +          ClassElement classElement = element; | 
| +          isNative = classElement.isNative(); | 
| +        } | 
| +        if (Elements.isInstanceField(element)) { | 
| +          isNative = element.isNative(); | 
| +        } | 
| +        String result = isNative ? guess : getFreshName(guess, usedGlobalNames); | 
| globals[element] = result; | 
| return result; | 
| } | 
| @@ -331,13 +433,12 @@ class Namer { | 
| } | 
|  | 
| String getLazyInitializerName(Element element) { | 
| -    // TODO(floitsch): mangle while not conflicting with other statics. | 
| assert(Elements.isStaticOrTopLevelField(element)); | 
| -    return "get\$${getName(element)}"; | 
| +    return getMappedGlobalName("get\$${getName(element)}"); | 
| } | 
|  | 
| String isolatePropertiesAccess(Element element) { | 
| -    return "$ISOLATE.$ISOLATE_PROPERTIES.${getName(element)}"; | 
| +    return "$isolateName.$isolatePropertiesName.${getName(element)}"; | 
| } | 
|  | 
| String isolateAccess(Element element) { | 
| @@ -345,7 +446,8 @@ class Namer { | 
| } | 
|  | 
| String isolateBailoutAccess(Element element) { | 
| -    return '${isolateAccess(element)}\$bailout'; | 
| +    String newName = getMappedGlobalName('${getName(element)}\$bailout'); | 
| +    return '$CURRENT_ISOLATE.$newName'; | 
| } | 
|  | 
| String isolateLazyInitializerAccess(Element element) { | 
| @@ -353,6 +455,7 @@ class Namer { | 
| } | 
|  | 
| String operatorIs(Element element) { | 
| +    // TODO(erikcorry): Reduce from is$x to ix when we are minifying. | 
| return 'is\$${getName(element)}'; | 
| } | 
|  | 
|  |