| Index: pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart
 | 
| diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart
 | 
| deleted file mode 100644
 | 
| index 5d7df35210e3da68bf1c1c7cc827ea5f54809393..0000000000000000000000000000000000000000
 | 
| --- a/pkg/compiler/lib/src/js_emitter/old_emitter/nsm_emitter.dart
 | 
| +++ /dev/null
 | 
| @@ -1,391 +0,0 @@
 | 
| -// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
 | 
| -// for details. All rights reserved. Use of this source code is governed by a
 | 
| -// BSD-style license that can be found in the LICENSE file.
 | 
| -
 | 
| -part of dart2js.js_emitter;
 | 
| -
 | 
| -class NsmEmitter extends CodeEmitterHelper {
 | 
| -  final List<Selector> trivialNsmHandlers = <Selector>[];
 | 
| -
 | 
| -  /// If this is true then we can generate the noSuchMethod handlers at startup
 | 
| -  /// time, instead of them being emitted as part of the Object class.
 | 
| -  bool get generateTrivialNsmHandlers => true;
 | 
| -
 | 
| -  // If we need fewer than this many noSuchMethod handlers we can save space by
 | 
| -  // just emitting them in JS, rather than emitting the JS needed to generate
 | 
| -  // them at run time.
 | 
| -  static const VERY_FEW_NO_SUCH_METHOD_HANDLERS = 10;
 | 
| -
 | 
| -  static const MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING = 4;
 | 
| -
 | 
| -  void emitNoSuchMethodHandlers(AddPropertyFunction addProperty) {
 | 
| -
 | 
| -    ClassStubGenerator generator =
 | 
| -        new ClassStubGenerator(compiler, namer, backend);
 | 
| -
 | 
| -    // Keep track of the JavaScript names we've already added so we
 | 
| -    // do not introduce duplicates (bad for code size).
 | 
| -    Map<jsAst.Name, Selector> addedJsNames
 | 
| -        = generator.computeSelectorsForNsmHandlers();
 | 
| -
 | 
| -    // Set flag used by generateMethod helper below.  If we have very few
 | 
| -    // handlers we use addProperty for them all, rather than try to generate
 | 
| -    // them at runtime.
 | 
| -    bool haveVeryFewNoSuchMemberHandlers =
 | 
| -        (addedJsNames.length < VERY_FEW_NO_SUCH_METHOD_HANDLERS);
 | 
| -    List<jsAst.Name> names = addedJsNames.keys.toList()
 | 
| -        ..sort();
 | 
| -    for (jsAst.Name jsName in names) {
 | 
| -      Selector selector = addedJsNames[jsName];
 | 
| -      String reflectionName = emitter.getReflectionName(selector, jsName);
 | 
| -
 | 
| -      if (reflectionName != null) {
 | 
| -        emitter.mangledFieldNames[jsName] = reflectionName;
 | 
| -      }
 | 
| -
 | 
| -      List<jsAst.Expression> argNames =
 | 
| -          selector.callStructure.getOrderedNamedArguments().map((String name) =>
 | 
| -              js.string(name)).toList();
 | 
| -      int type = selector.invocationMirrorKind;
 | 
| -      if (!haveVeryFewNoSuchMemberHandlers &&
 | 
| -          isTrivialNsmHandler(type, argNames, selector, jsName) &&
 | 
| -          reflectionName == null) {
 | 
| -        trivialNsmHandlers.add(selector);
 | 
| -      } else {
 | 
| -        StubMethod method =
 | 
| -            generator.generateStubForNoSuchMethod(jsName, selector);
 | 
| -        addProperty(method.name, method.code);
 | 
| -        if (reflectionName != null) {
 | 
| -          bool accessible =
 | 
| -              compiler.world.allFunctions.filter(selector, null).any(
 | 
| -              (Element e) => backend.isAccessibleByReflection(e));
 | 
| -          addProperty(namer.asName('+$reflectionName'),
 | 
| -                      js(accessible ? '2' : '0'));
 | 
| -        }
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  // Identify the noSuchMethod handlers that are so simple that we can
 | 
| -  // generate them programatically.
 | 
| -  bool isTrivialNsmHandler(
 | 
| -      int type, List argNames, Selector selector, jsAst.Name internalName) {
 | 
| -    if (!generateTrivialNsmHandlers) return false;
 | 
| -    // Check for named arguments.
 | 
| -    if (argNames.length != 0) return false;
 | 
| -    // Check for unexpected name (this doesn't really happen).
 | 
| -    if (internalName is GetterName) return type == 1;
 | 
| -    if (internalName is SetterName) return type == 2;
 | 
| -    return type == 0;
 | 
| -  }
 | 
| -
 | 
| -  /**
 | 
| -   * Adds (at runtime) the handlers to the Object class which catch calls to
 | 
| -   * methods that the object does not have.  The handlers create an invocation
 | 
| -   * mirror object.
 | 
| -   *
 | 
| -   * The current version only gives you the minified name when minifying (when
 | 
| -   * not minifying this method is not called).
 | 
| -   *
 | 
| -   * In order to generate the noSuchMethod handlers we only need the minified
 | 
| -   * name of the method.  We test the first character of the minified name to
 | 
| -   * determine if it is a getter or a setter, and we use the arguments array at
 | 
| -   * runtime to get the number of arguments and their values.  If the method
 | 
| -   * involves named arguments etc. then we don't handle it here, but emit the
 | 
| -   * handler method directly on the Object class.
 | 
| -   *
 | 
| -   * The minified names are mostly 1-4 character names, which we emit in sorted
 | 
| -   * order (primary key is length, secondary ordering is lexicographic).  This
 | 
| -   * gives an order like ... dD dI dX da ...
 | 
| -   *
 | 
| -   * Gzip is good with repeated text, but it can't diff-encode, so we do that
 | 
| -   * for it.  We encode the minified names in a comma-separated string, but all
 | 
| -   * the 1-4 character names are encoded before the first comma as a series of
 | 
| -   * base 26 numbers.  The last digit of each number is lower case, the others
 | 
| -   * are upper case, so 1 is "b" and 26 is "Ba".
 | 
| -   *
 | 
| -   * We think of the minified names as base 88 numbers using the ASCII
 | 
| -   * characters from # to z.  The base 26 numbers each encode the delta from
 | 
| -   * the previous minified name to the next.  So if there is a minified name
 | 
| -   * called Df and the next is Dh, then they are 2971 and 2973 when thought of
 | 
| -   * as base 88 numbers.  The difference is 2, which is "c" in lower-case-
 | 
| -   * terminated base 26.
 | 
| -   *
 | 
| -   * The reason we don't encode long minified names with this method is that
 | 
| -   * decoding the base 88 numbers would overflow JavaScript's puny integers.
 | 
| -   *
 | 
| -   * There are some selectors that have a special calling convention (because
 | 
| -   * they are called with the receiver as the first argument).  They need a
 | 
| -   * slightly different noSuchMethod handler, so we handle these first.
 | 
| -   */
 | 
| -  List<jsAst.Statement> buildTrivialNsmHandlers() {
 | 
| -    List<jsAst.Statement> statements = <jsAst.Statement>[];
 | 
| -    if (trivialNsmHandlers.length == 0) return statements;
 | 
| -
 | 
| -    bool minify = compiler.enableMinification;
 | 
| -    bool useDiffEncoding = minify && trivialNsmHandlers.length > 30;
 | 
| -
 | 
| -    // Find out how many selectors there are with the special calling
 | 
| -    // convention.
 | 
| -    Iterable<Selector> interceptedSelectors = trivialNsmHandlers.where(
 | 
| -            (Selector s) => backend.isInterceptedName(s.name));
 | 
| -    Iterable<Selector> ordinarySelectors = trivialNsmHandlers.where(
 | 
| -            (Selector s) => !backend.isInterceptedName(s.name));
 | 
| -
 | 
| -    // Get the short names (JS names, perhaps minified).
 | 
| -    Iterable<jsAst.Name> interceptedShorts =
 | 
| -        interceptedSelectors.map(namer.invocationMirrorInternalName);
 | 
| -    Iterable<jsAst.Name> ordinaryShorts =
 | 
| -        ordinarySelectors.map(namer.invocationMirrorInternalName);
 | 
| -
 | 
| -    jsAst.Expression sortedShorts;
 | 
| -    Iterable<String> sortedLongs;
 | 
| -    if (useDiffEncoding) {
 | 
| -      assert(minify);
 | 
| -      sortedShorts = new _DiffEncodedListOfNames(
 | 
| -          [interceptedShorts, ordinaryShorts]);
 | 
| -    } else {
 | 
| -      Iterable<Selector> sorted =
 | 
| -          [interceptedSelectors, ordinarySelectors].expand((e) => (e));
 | 
| -      sortedShorts = js.concatenateStrings(
 | 
| -          js.joinLiterals(
 | 
| -              sorted.map(namer.invocationMirrorInternalName),
 | 
| -              js.stringPart(",")),
 | 
| -          addQuotes: true);
 | 
| -
 | 
| -      if (!minify) {
 | 
| -        sortedLongs = sorted.map((selector) =>
 | 
| -            selector.invocationMirrorMemberName);
 | 
| -      }
 | 
| -    }
 | 
| -    // Startup code that loops over the method names and puts handlers on the
 | 
| -    // Object class to catch noSuchMethod invocations.
 | 
| -    ClassElement objectClass = compiler.objectClass;
 | 
| -    jsAst.Expression createInvocationMirror = backend.emitter
 | 
| -        .staticFunctionAccess(backend.getCreateInvocationMirror());
 | 
| -    if (useDiffEncoding) {
 | 
| -      statements.add(js.statement('''{
 | 
| -          var objectClassObject = processedClasses.collected[#objectClass],
 | 
| -              nameSequences = #diffEncoding.split("."),
 | 
| -              shortNames = [];
 | 
| -          if (objectClassObject instanceof Array)
 | 
| -              objectClassObject = objectClassObject[1];
 | 
| -          for (var j = 0; j < nameSequences.length; ++j) {
 | 
| -              var sequence = nameSequences[j].split(","),
 | 
| -                nameNumber = 0;
 | 
| -            // If we are loading a deferred library the object class will not be
 | 
| -            // in the collectedClasses so objectClassObject is undefined, and we
 | 
| -            // skip setting up the names.
 | 
| -            if (!objectClassObject) break;
 | 
| -            // Likewise, if the current sequence is empty, we don't process it.
 | 
| -            if (sequence.length == 0) continue;
 | 
| -            var diffEncodedString = sequence[0];
 | 
| -            for (var i = 0; i < diffEncodedString.length; i++) {
 | 
| -              var codes = [],
 | 
| -                  diff = 0,
 | 
| -                  digit = diffEncodedString.charCodeAt(i);
 | 
| -              for (; digit <= ${$Z};) {
 | 
| -                diff *= 26;
 | 
| -                diff += (digit - ${$A});
 | 
| -                digit = diffEncodedString.charCodeAt(++i);
 | 
| -              }
 | 
| -              diff *= 26;
 | 
| -              diff += (digit - ${$a});
 | 
| -              nameNumber += diff;
 | 
| -              for (var remaining = nameNumber;
 | 
| -                   remaining > 0;
 | 
| -                   remaining = (remaining / 88) | 0) {
 | 
| -                codes.unshift(${$HASH} + remaining % 88);
 | 
| -              }
 | 
| -              shortNames.push(
 | 
| -                String.fromCharCode.apply(String, codes));
 | 
| -            }
 | 
| -            if (sequence.length > 1) {
 | 
| -              Array.prototype.push.apply(shortNames, sequence.shift());
 | 
| -            }
 | 
| -          }
 | 
| -        }''', {'objectClass': js.quoteName(namer.className(objectClass)),
 | 
| -               'diffEncoding': sortedShorts}));
 | 
| -    } else {
 | 
| -      // No useDiffEncoding version.
 | 
| -      statements.add(js.statement(
 | 
| -          'var objectClassObject = processedClasses.collected[#objectClass],'
 | 
| -          '    shortNames = #diffEncoding.split(",")',
 | 
| -          {'objectClass': js.quoteName(namer.className(objectClass)),
 | 
| -           'diffEncoding': sortedShorts}));
 | 
| -      if (!minify) {
 | 
| -        statements.add(js.statement('var longNames = #longs.split(",")',
 | 
| -                {'longs': js.string(sortedLongs.join(','))}));
 | 
| -      }
 | 
| -      statements.add(js.statement(
 | 
| -          'if (objectClassObject instanceof Array)'
 | 
| -          '  objectClassObject = objectClassObject[1];'));
 | 
| -    }
 | 
| -
 | 
| -    dynamic isIntercepted =  // jsAst.Expression or bool.
 | 
| -        interceptedSelectors.isEmpty
 | 
| -        ? false
 | 
| -        : ordinarySelectors.isEmpty
 | 
| -            ? true
 | 
| -            : js('j < #', js.number(interceptedSelectors.length));
 | 
| -
 | 
| -    statements.add(js.statement('''
 | 
| -      // If we are loading a deferred library the object class will not be in
 | 
| -      // the collectedClasses so objectClassObject is undefined, and we skip
 | 
| -      // setting up the names.
 | 
| -      if (objectClassObject) {
 | 
| -        for (var j = 0; j < shortNames.length; j++) {
 | 
| -          var type = 0;
 | 
| -          var shortName = shortNames[j];
 | 
| -          if (shortName[0] == "${namer.getterPrefix[0]}") type = 1;
 | 
| -          if (shortName[0] == "${namer.setterPrefix[0]}") type = 2;
 | 
| -          // Generate call to:
 | 
| -          //
 | 
| -          //     createInvocationMirror(String name, internalName, type,
 | 
| -          //         arguments, argumentNames)
 | 
| -          //
 | 
| -
 | 
| -          // This 'if' is either a static choice or dynamic choice depending on
 | 
| -          // [isIntercepted].
 | 
| -          if (#isIntercepted) {
 | 
| -            objectClassObject[shortName] =
 | 
| -                (function(name, shortName, type) {
 | 
| -                  return function(receiver) {
 | 
| -                    return this.#noSuchMethodName(
 | 
| -                      receiver,
 | 
| -                      #createInvocationMirror(name, shortName, type,
 | 
| -                          // Create proper Array with all arguments except first
 | 
| -                          // (receiver).
 | 
| -                          Array.prototype.slice.call(arguments, 1),
 | 
| -                          []));
 | 
| -                  }
 | 
| -                 })(#names[j], shortName, type);
 | 
| -          } else {
 | 
| -            objectClassObject[shortName] =
 | 
| -                (function(name, shortName, type) {
 | 
| -                  return function() {
 | 
| -                    return this.#noSuchMethodName(
 | 
| -                      // Object.noSuchMethodName ignores the explicit receiver
 | 
| -                      // argument. We could pass anything in place of [this].
 | 
| -                      this,
 | 
| -                      #createInvocationMirror(name, shortName, type,
 | 
| -                          // Create proper Array with all arguments.
 | 
| -                          Array.prototype.slice.call(arguments, 0),
 | 
| -                          []));
 | 
| -                  }
 | 
| -                 })(#names[j], shortName, type);
 | 
| -          }
 | 
| -        }
 | 
| -      }''', {
 | 
| -          'noSuchMethodName': namer.noSuchMethodName,
 | 
| -          'createInvocationMirror': createInvocationMirror,
 | 
| -          'names': minify ? 'shortNames' : 'longNames',
 | 
| -          'isIntercepted': isIntercepted}));
 | 
| -
 | 
| -    return statements;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -/// When pretty printed, this node computes a diff-encoded string for the list
 | 
| -/// of given names.
 | 
| -///
 | 
| -/// See [buildTrivialNsmHandlers].
 | 
| -class _DiffEncodedListOfNames extends jsAst.DeferredString
 | 
| -                              implements jsAst.AstContainer {
 | 
| -  String _cachedValue;
 | 
| -  List<jsAst.ArrayInitializer> ast;
 | 
| -
 | 
| -  Iterable<jsAst.Node> get containedNodes => ast;
 | 
| -
 | 
| -  _DiffEncodedListOfNames(Iterable<Iterable<jsAst.Name>> names) {
 | 
| -    // Store the names in ArrayInitializer nodes to make them discoverable
 | 
| -    // by traversals of the ast.
 | 
| -    ast = names.map((Iterable i) => new jsAst.ArrayInitializer(i.toList()))
 | 
| -               .toList();
 | 
| -  }
 | 
| -
 | 
| -  void _computeDiffEncodingForList(Iterable<jsAst.Name> names,
 | 
| -                                   StringBuffer diffEncoding) {
 | 
| -    // Treat string as a number in base 88 with digits in ASCII order from # to
 | 
| -    // z.  The short name sorting is based on length, and uses ASCII order for
 | 
| -    // equal length strings so this means that names are ascending.  The hash
 | 
| -    // character, #, is never given as input, but we need it because it's the
 | 
| -    // implicit leading zero (otherwise we could not code names with leading
 | 
| -    // dollar signs).
 | 
| -    int fromBase88(String x) {
 | 
| -      int answer = 0;
 | 
| -      for (int i = 0; i < x.length; i++) {
 | 
| -        int c = x.codeUnitAt(i);
 | 
| -        // No support for Unicode minified identifiers in JS.
 | 
| -        assert(c >= $$ && c <= $z);
 | 
| -        answer *= 88;
 | 
| -        answer += c - $HASH;
 | 
| -      }
 | 
| -      return answer;
 | 
| -    }
 | 
| -
 | 
| -    // Big endian encoding, A = 0, B = 1...
 | 
| -    // A lower case letter terminates the number.
 | 
| -    String toBase26(int x) {
 | 
| -      int c = x;
 | 
| -      var encodingChars = <int>[];
 | 
| -      encodingChars.add($a + (c % 26));
 | 
| -      while (true) {
 | 
| -        c ~/= 26;
 | 
| -        if (c == 0) break;
 | 
| -        encodingChars.add($A + (c % 26));
 | 
| -      }
 | 
| -      return new String.fromCharCodes(encodingChars.reversed.toList());
 | 
| -    }
 | 
| -
 | 
| -    // Sort by length, then lexicographic.
 | 
| -    int compare(String a, String b) {
 | 
| -      if (a.length != b.length) return a.length - b.length;
 | 
| -      return a.compareTo(b);
 | 
| -    }
 | 
| -
 | 
| -    List<String> shorts =
 | 
| -        names.map((jsAst.Name name) => name.name)
 | 
| -        .toList()
 | 
| -        ..sort(compare);
 | 
| -
 | 
| -    int previous = 0;
 | 
| -    for (String short in shorts) {
 | 
| -      if (short.length <= NsmEmitter.MAX_MINIFIED_LENGTH_FOR_DIFF_ENCODING) {
 | 
| -        int base63 = fromBase88(short);
 | 
| -        int diff = base63 - previous;
 | 
| -        previous = base63;
 | 
| -        String base26Diff = toBase26(diff);
 | 
| -        diffEncoding.write(base26Diff);
 | 
| -      } else {
 | 
| -        if (diffEncoding.length != 0) {
 | 
| -          diffEncoding.write(',');
 | 
| -        }
 | 
| -        diffEncoding.write(short);
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  String _computeDiffEncoding() {
 | 
| -    StringBuffer buffer = new StringBuffer();
 | 
| -    for (jsAst.ArrayInitializer list in ast) {
 | 
| -      if (buffer.isNotEmpty) {
 | 
| -        // Emit period that resets the diff base to zero when we switch to
 | 
| -        // normal calling convention (this avoids the need to code negative
 | 
| -        // diffs).
 | 
| -        buffer.write(".");
 | 
| -      }
 | 
| -      List<jsAst.Name> names = list.elements;
 | 
| -      _computeDiffEncodingForList(names, buffer);
 | 
| -    }
 | 
| -    return '"${buffer.toString()}"';
 | 
| -  }
 | 
| -
 | 
| -  String get value {
 | 
| -    if (_cachedValue == null) {
 | 
| -      _cachedValue = _computeDiffEncoding();
 | 
| -    }
 | 
| -
 | 
| -    return _cachedValue;
 | 
| -  }
 | 
| -}
 | 
| 
 |