Version 1.2.0-dev.3.0

svn merge -r 32187:32420 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@32426 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/client/tools/buildbot_annotated_steps.py b/client/tools/buildbot_annotated_steps.py
index a6f1c1f..130d1e5 100755
--- a/client/tools/buildbot_annotated_steps.py
+++ b/client/tools/buildbot_annotated_steps.py
@@ -204,6 +204,8 @@
   elif name.startswith('cross') or name.startswith('target'):
     status = ProcessBot(name, 'cross-vm',
                         custom_env=EnvironmentWithoutBotoConfig())
+  elif name.startswith('src-tarball'):
+    status = ProcessBot(name, 'src-tarball')
   else:
     status = ProcessBot(name, 'compiler')
 
diff --git a/dart.gyp b/dart.gyp
index 914b088..0ed89c0 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -120,9 +120,6 @@
       'target_name': 'api_docs',
       'type': 'none',
       'dependencies': [
-        # TODO(alanknight) : Once we're fully switched over to the new
-        # viewer remove the old api_docs gyp file.
-        'utils/apidoc/apidoc.gyp:api_docs',
         'utils/apidoc/docgen.gyp:docgen',
       ],
     },
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
index 08d89ec..5827d47 100644
--- a/pkg/analysis_server/lib/src/protocol.dart
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -55,7 +55,7 @@
    * Return a request parsed from the given [data], or `null` if the [data] is
    * not a valid json representation of a request. The [data] is expected to
    * have the following format:
-   * 
+   *
    *   {
    *     'id': String,
    *     'method': methodName,
@@ -63,7 +63,7 @@
    *       paramter_name: value
    *     }
    *   }
-   * 
+   *
    * where the parameters are optional and can contain any number of name/value
    * pairs.
    */
@@ -115,7 +115,7 @@
   /**
    * Convert the given [value] to a boolean, or throw a [RequestFailure]
    * exception if the [value] could not be converted.
-   * 
+   *
    * The value is typically the result of invoking either [getParameter] or
    * [getRequiredParameter].
    */
@@ -131,7 +131,7 @@
   /**
    * Convert the given [value] to an integer, or throw a [RequestFailure]
    * exception if the [value] could not be converted.
-   * 
+   *
    * The value is typically the result of invoking either [getParameter] or
    * [getRequiredParameter].
    */
@@ -177,7 +177,7 @@
    * The error that was caused by attempting to handle the request, or `null` if
    * there was no error.
    */
-  final Object error;
+  final RequestError error;
 
   /**
    * A table mapping the names of result fields to their values. The table
@@ -197,7 +197,7 @@
    * by a [request] referencing a context that does not exist.
    */
   Response.contextDoesNotExist(Request request)
-    : this(request.id, 'Context does not exist');
+    : this(request.id, new RequestError(-1, 'Context does not exist'));
 
   /**
    * Initialize a newly created instance to represent an error condition caused
@@ -205,7 +205,7 @@
    * passed a non-boolean value.
    */
   Response.expectedBoolean(Request request, String value)
-    : this(request.id, 'Expected a boolean value, but found "$value"');
+    : this(request.id, new RequestError(-2, 'Expected a boolean value, but found "$value"'));
 
   /**
    * Initialize a newly created instance to represent an error condition caused
@@ -213,21 +213,21 @@
    * passed a non-integer value.
    */
   Response.expectedInteger(Request request, String value)
-    : this(request.id, 'Expected an integer value, but found "$value"');
+    : this(request.id, new RequestError(-3, 'Expected an integer value, but found "$value"'));
 
   /**
    * Initialize a newly created instance to represent an error condition caused
    * by a malformed request.
    */
   Response.invalidRequestFormat()
-    : this('', 'Invalid request');
+    : this('', new RequestError(-4, 'Invalid request'));
 
   /**
    * Initialize a newly created instance to represent an error condition caused
    * by a [request] that does not have a required parameter.
    */
   Response.missingRequiredParameter(Request request, String parameterName)
-    : this(request.id, 'Missing required parameter: $parameterName');
+    : this(request.id, new RequestError(-5, 'Missing required parameter: $parameterName'));
 
   /**
    * Initialize a newly created instance to represent an error condition caused
@@ -235,14 +235,14 @@
    * unknown analysis option was provided.
    */
   Response.unknownAnalysisOption(Request request, String optionName)
-    : this(request.id, 'Unknown analysis option: "$optionName"');
+    : this(request.id, new RequestError(-6, 'Unknown analysis option: "$optionName"'));
 
   /**
    * Initialize a newly created instance to represent an error condition caused
    * by a [request] that cannot be handled by any known handlers.
    */
   Response.unknownRequest(Request request)
-    : this(request.id, 'Unknown request');
+    : this(request.id, new RequestError(-7, 'Unknown request'));
 
   /**
    * Return the value of the result field with the given [name].
@@ -265,7 +265,11 @@
   Map<String, Object> toJson() {
     Map jsonObject = new Map();
     jsonObject[ID] = id;
-    jsonObject[ERROR] = error;
+    if (error == null) {
+      jsonObject[ERROR] = null;
+    } else {
+      jsonObject[ERROR] = error.toJson();
+    }
     if (!result.isEmpty) {
       jsonObject[RESULT] = result;
     }
@@ -274,6 +278,139 @@
 }
 
 /**
+ * Instances of the class [RequestError] represent information about an error that
+ * occurred while attempting to respond to a [Request].
+ */
+class RequestError {
+  /**
+   * The name of the JSON attribute containing the code that uniquely identifies
+   * the error that occurred.
+   */
+  static const String CODE = 'code';
+
+  /**
+   * The name of the JSON attribute containing an object with additional data
+   * related to the error.
+   */
+  static const String DATA = 'data';
+
+  /**
+   * The name of the JSON attribute containing a short description of the error.
+   */
+  static const String MESSAGE = 'message';
+
+  /**
+   * An error code indicating a parse error. Invalid JSON was received by the
+   * server. An error occurred on the server while parsing the JSON text.
+   */
+  static const int CODE_PARSE_ERROR = -32700;
+
+  /**
+   * An error code indicating an invalid request. The JSON sent is not a valid
+   * [Request] object.
+   */
+  static const int CODE_INVALID_REQUEST = -32600;
+
+  /**
+   * An error code indicating a method not found. The method does not exist or
+   * is not currently available.
+   */
+  static const int CODE_METHOD_NOT_FOUND = -32601;
+
+  /**
+   * An error code indicating one or more invalid parameters.
+   */
+  static const int CODE_INVALID_PARAMS = -32602;
+
+  /**
+   * An error code indicating an internal error.
+   */
+  static const int CODE_INTERNAL_ERROR = -32603;
+
+  /*
+   * In addition, codes -32000 to -32099 indicate a server error. They are
+   * reserved for implementation-defined server-errors.
+   */
+
+  /**
+   * The code that uniquely identifies the error that occurred.
+   */
+  final int code;
+
+  /**
+   * A short description of the error.
+   */
+  final String message;
+
+  /**
+   * A table mapping the names of notification parameters to their values.
+   */
+  final Map<String, Object> data = new Map<String, Object>();
+
+  /**
+   * Initialize a newly created [Error] to have the given [code] and [message].
+   */
+  RequestError(this.code, this.message);
+
+  /**
+   * Initialize a newly created [Error] to indicate a parse error. Invalid JSON
+   * was received by the server. An error occurred on the server while parsing
+   * the JSON text.
+   */
+  RequestError.parseError() : this(CODE_PARSE_ERROR, "Parse error");
+
+  /**
+   * Initialize a newly created [Error] to indicate an invalid request. The
+   * JSON sent is not a valid [Request] object.
+   */
+  RequestError.invalidRequest() : this(CODE_INVALID_REQUEST, "Invalid request");
+
+  /**
+   * Initialize a newly created [Error] to indicate that a method was not found.
+   * Either the method does not exist or is not currently available.
+   */
+  RequestError.methodNotFound() : this(CODE_METHOD_NOT_FOUND, "Method not found");
+
+  /**
+   * Initialize a newly created [Error] to indicate one or more invalid
+   * parameters.
+   */
+  RequestError.invalidParameters() : this(CODE_INVALID_PARAMS, "Invalid parameters");
+
+  /**
+   * Initialize a newly created [Error] to indicate an internal error.
+   */
+  RequestError.internalError() : this(CODE_INTERNAL_ERROR, "Internal error");
+
+  /**
+   * Return the value of the data with the given [name], or `null` if there is
+   * no such data associated with this error.
+   */
+  Object getData(String name) => data[name];
+
+  /**
+   * Set the value of the data with the given [name] to the given [value].
+   */
+  void setData(String name, Object value) {
+    data[name] = value;
+  }
+
+  /**
+   * Return a table representing the structure of the Json object that will be
+   * sent to the client to represent this response.
+   */
+  Map<String, Object> toJson() {
+    Map jsonObject = new Map();
+    jsonObject[CODE] = code;
+    jsonObject[MESSAGE] = message;
+    if (!data.isEmpty) {
+      jsonObject[DATA] = data;
+    }
+    return jsonObject;
+  }
+}
+
+/**
  * Instances of the class [Notification] represent a notification from the
  * server about an event that occurred.
  */
diff --git a/pkg/analysis_server/test/protocol_test.dart b/pkg/analysis_server/test/protocol_test.dart
index 9909031..2bb24fd 100644
--- a/pkg/analysis_server/test/protocol_test.dart
+++ b/pkg/analysis_server/test/protocol_test.dart
@@ -61,7 +61,7 @@
     expect(response.error, isNotNull);
     expect(response.toJson(), equals({
       Response.ID: '0',
-      Response.ERROR: 'Context does not exist'
+      Response.ERROR: {'code': -1, 'message': 'Context does not exist'}
     }));
   }
 
@@ -71,7 +71,7 @@
     expect(response.error, isNotNull);
     expect(response.toJson(), equals({
       Response.ID: '',
-      Response.ERROR: 'Invalid request'
+      Response.ERROR: {'code': -4, 'message': 'Invalid request'}
     }));
   }
 
@@ -81,7 +81,7 @@
     expect(response.error, isNotNull);
     expect(response.toJson(), equals({
       Response.ID: '0',
-      Response.ERROR: 'Missing required parameter: x'
+      Response.ERROR: {'code': -5, 'message': 'Missing required parameter: x'}
     }));
   }
 
@@ -91,7 +91,7 @@
     expect(response.error, isNotNull);
     expect(response.toJson(), equals({
       Response.ID: '0',
-      Response.ERROR: 'Unknown request'
+      Response.ERROR: {'code': -7, 'message': 'Unknown request'}
     }));
   }
 
diff --git a/pkg/analyzer/bin/analyzer.dart b/pkg/analyzer/bin/analyzer.dart
index 2ce52a5..76510c0 100644
--- a/pkg/analyzer/bin/analyzer.dart
+++ b/pkg/analyzer/bin/analyzer.dart
@@ -47,13 +47,12 @@
       print("angular:$angularTime");
       print("other:${totalTime
         - (scanTime + parseTime + resolveTime + errorsTime + hintsTime
-           + angularTime)}}");
+           + angularTime)}");
       print("total:$totalTime");
       print("");
       print("Time spent in instanceof = ${instanceOfTimer.elapsedMilliseconds}");
     }
-
-    exit(result.ordinal);
+    exitCode = result.ordinal;
   }
 }
 
diff --git a/pkg/analyzer/example/parser_driver.dart b/pkg/analyzer/example/parser_driver.dart
index e69197b..4c93836 100644
--- a/pkg/analyzer/example/parser_driver.dart
+++ b/pkg/analyzer/example/parser_driver.dart
@@ -6,7 +6,6 @@
 
 import 'dart:io';
 
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
@@ -31,7 +30,7 @@
 _parse(File file) {
   var src = file.readAsStringSync();
   var errorListener = new _ErrorCollector();
-  var reader = new CharSequenceReader(new CharSequence(src));
+  var reader = new CharSequenceReader(src);
   var scanner = new Scanner(null, reader, errorListener);
   var token = scanner.tokenize();
   var parser = new Parser(null, errorListener);
diff --git a/pkg/analyzer/example/scanner_driver.dart b/pkg/analyzer/example/scanner_driver.dart
index a19c6eb..8eccee9 100644
--- a/pkg/analyzer/example/scanner_driver.dart
+++ b/pkg/analyzer/example/scanner_driver.dart
@@ -7,7 +7,6 @@
 import 'dart:io';
 
 import 'package:analyzer/src/generated/scanner.dart';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
 
 main(List<String> args) {
 
@@ -26,7 +25,7 @@
 
 _scan(File file) {
   var src = file.readAsStringSync();
-  var reader = new CharSequenceReader(new CharSequence(src));
+  var reader = new CharSequenceReader(src);
   var scanner = new Scanner(null, reader, null);
   var token = scanner.tokenize();
   while (token.type != TokenType.EOF) {
diff --git a/pkg/analyzer/lib/analyzer.dart b/pkg/analyzer/lib/analyzer.dart
index be32717..5572950 100644
--- a/pkg/analyzer/lib/analyzer.dart
+++ b/pkg/analyzer/lib/analyzer.dart
@@ -8,7 +8,6 @@
 
 import 'package:path/path.dart' as pathos;
 
-import 'src/generated/java_core.dart' show CharSequence;
 import 'src/error.dart';
 import 'src/generated/ast.dart';
 import 'src/generated/error.dart';
@@ -37,7 +36,7 @@
     throw new ArgumentError("Source $source doesn't exist");
   }
 
-  var reader = new CharSequenceReader(new CharSequence(contents));
+  var reader = new CharSequenceReader(contents);
   var scanner = new Scanner(source, reader, errorCollector);
   var token = scanner.tokenize();
   var parser = new Parser(source, errorCollector);
@@ -57,7 +56,7 @@
   if (name == null) name = '<unknown source>';
   var source = new StringSource(contents, name);
   var errorCollector = new _ErrorCollector();
-  var reader = new CharSequenceReader(new CharSequence(contents));
+  var reader = new CharSequenceReader(contents);
   var scanner = new Scanner(source, reader, errorCollector);
   var token = scanner.tokenize();
   var parser = new Parser(source, errorCollector);
diff --git a/pkg/analyzer/lib/src/analyzer_impl.dart b/pkg/analyzer/lib/src/analyzer_impl.dart
index 7f79c5d..1c63f03 100644
--- a/pkg/analyzer/lib/src/analyzer_impl.dart
+++ b/pkg/analyzer/lib/src/analyzer_impl.dart
@@ -6,6 +6,8 @@
 
 import 'dart:io';
 
+import 'package:path/path.dart' as pathos;
+
 import 'generated/java_io.dart';
 import 'generated/engine.dart';
 import 'generated/error.dart';
@@ -128,10 +130,9 @@
 
   void addLibrarySources(LibraryElement library, Set<LibraryElement> libraries,
       Set<CompilationUnitElement> units) {
-    if (library == null || libraries.contains(library)) {
+    if (library == null || !libraries.add(library) ) {
       return;
     }
-    libraries.add(library);
     // may be skip library
     {
       UriKind uriKind = library.source.uriKind;
@@ -192,9 +193,14 @@
     // may be file in SDK
     if (sdk is DirectoryBasedDartSdk) {
       DirectoryBasedDartSdk directoryBasedSdk = sdk;
-      String sdkLibPath = directoryBasedSdk.libraryDirectory.getPath() + JavaFile.separator;
-      if (file.getPath().startsWith(sdkLibPath)) {
-        return UriKind.DART_URI;
+      var libraryDirectory = directoryBasedSdk.libraryDirectory.getAbsolutePath();
+      var sdkLibPath = libraryDirectory + pathos.separator;
+      var filePath = file.getPath();
+      if (filePath.startsWith(sdkLibPath)) {
+        var internalPath = pathos.join(libraryDirectory, '_internal') + pathos.separator;
+        if (!filePath.startsWith(internalPath)) {
+          return UriKind.DART_URI;
+        }
       }
     }
     // some generic file
diff --git a/pkg/analyzer/lib/src/error.dart b/pkg/analyzer/lib/src/error.dart
index 5deee45..4c9b7af 100644
--- a/pkg/analyzer/lib/src/error.dart
+++ b/pkg/analyzer/lib/src/error.dart
@@ -7,7 +7,6 @@
 import 'dart:math' as math;
 
 import 'generated/error.dart';
-import 'generated/java_core.dart';
 import 'generated/source.dart';
 
 /// The maximum line length when printing extracted source code when converting
@@ -97,8 +96,6 @@
 
   String get result => _buffer.toString();
 
-  void accept(CharBuffer contents, _) =>
-    _buffer.write(contents.subSequence(0, contents.length()));
-
-  void accept2(String contents, _) => _buffer.write(contents);
+  void accept(String contents, _) =>
+    _buffer.write(contents.substring(0, contents.length));
 }
diff --git a/pkg/analyzer/lib/src/generated/ast.dart b/pkg/analyzer/lib/src/generated/ast.dart
index b4c10ce..c7f631c 100644
--- a/pkg/analyzer/lib/src/generated/ast.dart
+++ b/pkg/analyzer/lib/src/generated/ast.dart
@@ -4281,6 +4281,11 @@
  */
 abstract class Expression extends ASTNode {
   /**
+   * An empty array of expressions.
+   */
+  static List<Expression> EMPTY_ARRAY = new List<Expression>(0);
+
+  /**
    * The static type of this expression, or `null` if the AST structure has not been resolved.
    */
   Type2 staticType;
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 4ecc945..597ceeb 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -1154,6 +1154,12 @@
  */
 abstract class HtmlElement implements Element {
   /**
+   * Return the [CompilationUnitElement] associated with this Angular HTML file, maybe
+   * `null` if not an Angular file.
+   */
+  CompilationUnitElement get angularCompilationUnit;
+
+  /**
    * Return an array containing all of the script elements contained in the HTML file. This includes
    * scripts with libraries that are defined by the content of a script tag as well as libraries
    * that are referenced in the {@core source} attribute of a script tag.
@@ -1342,6 +1348,13 @@
   bool hasExtUri();
 
   /**
+   * Return `true` if this library is created for Angular analysis.
+   *
+   * @return `true` if this library is created for Angular analysis
+   */
+  bool get isAngularHtml;
+
+  /**
    * Answer `true` if this library is an application that can be run in the browser.
    *
    * @return `true` if this library is an application that can be run in the browser
@@ -4177,37 +4190,39 @@
   }
 
   void appendTo(JavaStringBuilder builder) {
-    builder.append("(");
-    String closing = null;
-    ParameterKind kind = ParameterKind.REQUIRED;
-    int parameterCount = _parameters.length;
-    for (int i = 0; i < parameterCount; i++) {
-      if (i > 0) {
-        builder.append(", ");
-      }
-      ParameterElementImpl parameter = _parameters[i] as ParameterElementImpl;
-      ParameterKind parameterKind = parameter.parameterKind;
-      if (parameterKind != kind) {
-        if (closing != null) {
-          builder.append(closing);
+    if (this.kind != ElementKind.GETTER) {
+      builder.append("(");
+      String closing = null;
+      ParameterKind kind = ParameterKind.REQUIRED;
+      int parameterCount = _parameters.length;
+      for (int i = 0; i < parameterCount; i++) {
+        if (i > 0) {
+          builder.append(", ");
         }
-        if (identical(parameterKind, ParameterKind.POSITIONAL)) {
-          builder.append("[");
-          closing = "]";
-        } else if (identical(parameterKind, ParameterKind.NAMED)) {
-          builder.append("{");
-          closing = "}";
-        } else {
-          closing = null;
+        ParameterElementImpl parameter = _parameters[i] as ParameterElementImpl;
+        ParameterKind parameterKind = parameter.parameterKind;
+        if (parameterKind != kind) {
+          if (closing != null) {
+            builder.append(closing);
+          }
+          if (identical(parameterKind, ParameterKind.POSITIONAL)) {
+            builder.append("[");
+            closing = "]";
+          } else if (identical(parameterKind, ParameterKind.NAMED)) {
+            builder.append("{");
+            closing = "}";
+          } else {
+            closing = null;
+          }
         }
+        kind = parameterKind;
+        parameter.appendToWithoutDelimiters(builder);
       }
-      kind = parameterKind;
-      parameter.appendToWithoutDelimiters(builder);
+      if (closing != null) {
+        builder.append(closing);
+      }
+      builder.append(")");
     }
-    if (closing != null) {
-      builder.append(closing);
-    }
-    builder.append(")");
     if (type != null) {
       builder.append(Element.RIGHT_ARROW);
       builder.append(type.returnType);
@@ -4626,6 +4641,12 @@
   Source source;
 
   /**
+   * The element associated with Dart pieces in this HTML unit or `null` if the receiver is
+   * not resolved.
+   */
+  CompilationUnitElement angularCompilationUnit;
+
+  /**
    * Initialize a newly created HTML element to have the given name.
    *
    * @param context the analysis context in which the HTML file is defined
@@ -4899,6 +4920,11 @@
   List<CompilationUnitElement> _parts = CompilationUnitElementImpl.EMPTY_ARRAY;
 
   /**
+   * Is `true` if this library is created for Angular analysis.
+   */
+  bool _isAngularHtml2 = false;
+
+  /**
    * Initialize a newly created library element to have the given name.
    *
    * @param context the analysis context in which the library is defined
@@ -5015,6 +5041,8 @@
 
   int get hashCode => _definingCompilationUnit.hashCode;
 
+  bool get isAngularHtml => _isAngularHtml2;
+
   bool get isBrowserApplication => entryPoint != null && isOrImportsBrowserLibrary;
 
   bool get isDartCore => name == "dart.core";
@@ -5027,6 +5055,13 @@
   }
 
   /**
+   * Specifies if this library is created for Angular analysis.
+   */
+  void set angularHtml(bool isAngularHtml) {
+    this._isAngularHtml2 = isAngularHtml;
+  }
+
+  /**
    * Set the compilation unit that defines this library to the given compilation unit.
    *
    * @param definingCompilationUnit the compilation unit that defines this library
@@ -6244,6 +6279,11 @@
  */
 class AngularComponentElementImpl extends AngularHasSelectorElementImpl implements AngularComponentElement {
   /**
+   * The offset of the defining <code>NgComponent</code> annotation.
+   */
+  int _annotationOffset = 0;
+
+  /**
    * The array containing all of the properties declared by this component.
    */
   List<AngularPropertyElement> _properties = AngularPropertyElement.EMPTY_ARRAY;
@@ -6280,7 +6320,9 @@
    * @param nameOffset the offset of the name of this element in the file that contains the
    *          declaration of this element
    */
-  AngularComponentElementImpl(String name, int nameOffset) : super(name, nameOffset);
+  AngularComponentElementImpl(String name, int nameOffset, int annotationOffset) : super(name, nameOffset) {
+    this._annotationOffset = annotationOffset;
+  }
 
   accept(ElementVisitor visitor) => visitor.visitAngularComponentElement(this);
 
@@ -6304,6 +6346,8 @@
     safelyVisitChildren(_properties, visitor);
     super.visitChildren(visitor);
   }
+
+  String get identifier => "AngularComponent@${_annotationOffset}";
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 1b226dc..a2cc12b 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -408,16 +408,6 @@
   List<Source> getLibrariesDependingOn(Source librarySource);
 
   /**
-   * Return the [AngularElement]s accessible in the library defined by the given source, or an
-   * empty array if given source is not a library, not resolved or cannot be analyzed for some
-   * reason.
-   *
-   * @param source the source defining the library whose [AngularElement]s is to be returned
-   * @return the [AngularElement]s accessible in the library defined by the given source
-   */
-  List<AngularElement> getLibraryAngularElements(Source source);
-
-  /**
    * Return the element model corresponding to the library defined by the given source, or
    * `null` if the element model does not currently exist or if the library cannot be analyzed
    * for some reason.
@@ -1015,11 +1005,11 @@
   }
 
   /**
-   * Record that the given source was just accessed.
+   * Record that the AST associated with the given source was just read from the cache.
    *
-   * @param source the source that was accessed
+   * @param source the source whose AST was accessed
    */
-  void accessed(Source source) {
+  void accessedAst(Source source) {
     if (_recentlyUsed.remove(source)) {
       _recentlyUsed.add(source);
       return;
@@ -1065,10 +1055,20 @@
    * @param source the source to be removed
    */
   void remove(Source source) {
+    _recentlyUsed.remove(source);
     _sourceMap.remove(source);
   }
 
   /**
+   * Record that the AST associated with the given source was just removed from the cache.
+   *
+   * @param source the source whose AST was removed
+   */
+  void removedAst(Source source) {
+    _recentlyUsed.remove(source);
+  }
+
+  /**
    * Set the maximum size of the cache to the given size.
    *
    * @param size the maximum number of sources for which AST structures should be kept in the cache
@@ -1090,6 +1090,23 @@
   int size() => _sourceMap.length;
 
   /**
+   * Record that the AST associated with the given source was just stored to the cache.
+   *
+   * @param source the source whose AST was stored
+   */
+  void storedAst(Source source) {
+    if (_recentlyUsed.contains(source)) {
+      return;
+    }
+    while (_recentlyUsed.length >= _maxCacheSize) {
+      if (!flushAstFromCache()) {
+        break;
+      }
+    }
+    _recentlyUsed.add(source);
+  }
+
+  /**
    * Attempt to flush one AST structure from the cache.
    *
    * @return `true` if a structure was flushed
@@ -1102,7 +1119,7 @@
     SourceEntry sourceEntry = _sourceMap[removedSource];
     if (sourceEntry is HtmlEntry) {
       HtmlEntryImpl htmlCopy = sourceEntry.writableCopy;
-      htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.FLUSHED);
+      htmlCopy.flushAstStructures();
       _sourceMap[removedSource] = htmlCopy;
     } else if (sourceEntry is DartEntry) {
       DartEntryImpl dartCopy = sourceEntry.writableCopy;
@@ -1139,6 +1156,17 @@
 }
 
 /**
+ * Information about Angular application.
+ */
+class AngularApplicationInfo {
+  final Source entryPoint;
+
+  final List<AngularElement> elements;
+
+  AngularApplicationInfo(this.entryPoint, this.elements);
+}
+
+/**
  * Instances of the class `CacheRetentionPolicy` define the behavior of objects that determine
  * how important it is for data to be retained in the analysis cache.
  */
@@ -1225,10 +1253,9 @@
  */
 abstract class DartEntry implements SourceEntry {
   /**
-   * The data descriptor representing the Angular elements accessible in the library. This data is
-   * only available for Dart files that are the defining compilation unit of a library.
+   * The data descriptor representing the list of libraries that contain this compilation unit.
    */
-  static final DataDescriptor<List<AngularElement>> ANGULAR_ELEMENTS = new DataDescriptor<List<AngularElement>>("DartEntry.ANGULAR_ELEMENTS");
+  static final DataDescriptor<List<Source>> CONTAINING_LIBRARIES = new DataDescriptor<List<Source>>("DartEntry.CONTAINING_LIBRARIES");
 
   /**
    * The data descriptor representing the library element for the library. This data is only
@@ -1449,6 +1476,12 @@
   List<Source> _includedParts = Source.EMPTY_ARRAY;
 
   /**
+   * The list of libraries that contain this compilation unit. The list will be empty if there are
+   * no known libraries that contain this compilation unit.
+   */
+  List<Source> _containingLibraries = new List<Source>();
+
+  /**
    * The information known as a result of resolving this compilation unit as part of the library
    * that contains this unit. This field will never be `null`.
    */
@@ -1465,17 +1498,6 @@
   LibraryElement _element;
 
   /**
-   * The state of the cached [angularElements].
-   */
-  CacheState _angularElementsState = CacheState.INVALID;
-
-  /**
-   * The array of Angular elements accessible in the library, or an empty array if the elements are
-   * not currently cached.
-   */
-  List<AngularElement> _angularElements = AngularElement.EMPTY_ARRAY;
-
-  /**
    * The state of the cached public namespace.
    */
   CacheState _publicNamespaceState = CacheState.INVALID;
@@ -1514,6 +1536,16 @@
   static int _CLIENT_CODE_INDEX = 2;
 
   /**
+   * Add the given library to the list of libraries that contain this part. This method should only
+   * be invoked on entries that represent a part.
+   *
+   * @param librarySource the source of the library to be added
+   */
+  void addContainingLibrary(Source librarySource) {
+    _containingLibraries.add(librarySource);
+  }
+
+  /**
    * Flush any AST structures being maintained by this entry.
    */
   void flushAstStructures() {
@@ -1616,9 +1648,7 @@
   }
 
   CacheState getState(DataDescriptor descriptor) {
-    if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
-      return _angularElementsState;
-    } else if (identical(descriptor, DartEntry.ELEMENT)) {
+    if (identical(descriptor, DartEntry.ELEMENT)) {
       return _elementState;
     } else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
       return _exportedLibrariesState;
@@ -1670,8 +1700,8 @@
   }
 
   Object getValue(DataDescriptor descriptor) {
-    if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
-      return _angularElements;
+    if (identical(descriptor, DartEntry.CONTAINING_LIBRARIES)) {
+      return new List.from(_containingLibraries);
     } else if (identical(descriptor, DartEntry.ELEMENT)) {
       return _element;
     } else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
@@ -1921,8 +1951,6 @@
    * not change the state of any parse results.
    */
   void recordResolutionError() {
-    _angularElements = AngularElement.EMPTY_ARRAY;
-    _angularElementsState = CacheState.ERROR;
     _element = null;
     _elementState = CacheState.ERROR;
     _bitmask = 0;
@@ -1938,9 +1966,6 @@
    * invalidated before they could be recorded.
    */
   void recordResolutionNotInProcess() {
-    if (identical(_angularElementsState, CacheState.IN_PROCESS)) {
-      _angularElementsState = CacheState.INVALID;
-    }
     if (identical(_elementState, CacheState.IN_PROCESS)) {
       _elementState = CacheState.INVALID;
     }
@@ -1957,6 +1982,16 @@
   }
 
   /**
+   * Remove the given library from the list of libraries that contain this part. This method should
+   * only be invoked on entries that represent a part.
+   *
+   * @param librarySource the source of the library to be removed
+   */
+  void removeContainingLibrary(Source librarySource) {
+    _containingLibraries.remove(librarySource);
+  }
+
+  /**
    * Remove any resolution information associated with this compilation unit being part of the given
    * library, presumably because it is no longer part of the library.
    *
@@ -1987,6 +2022,17 @@
   }
 
   /**
+   * Set the list of libraries that contain this compilation unit to contain only the given source.
+   * This method should only be invoked on entries that represent a library.
+   *
+   * @param librarySource the source of the single library that the list should contain
+   */
+  void set containingLibrary(Source librarySource) {
+    _containingLibraries.clear();
+    _containingLibraries.add(librarySource);
+  }
+
+  /**
    * Set the results of parsing the compilation unit at the given time to the given values.
    *
    * @param modificationStamp the earliest time at which the source was last modified before the
@@ -2011,10 +2057,7 @@
   }
 
   void setState(DataDescriptor descriptor, CacheState state) {
-    if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
-      _angularElements = updatedValue(state, _angularElements, AngularElement.EMPTY_ARRAY);
-      _angularElementsState = state;
-    } else if (identical(descriptor, DartEntry.ELEMENT)) {
+    if (identical(descriptor, DartEntry.ELEMENT)) {
       _element = updatedValue(state, _element, null);
       _elementState = state;
     } else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
@@ -2082,10 +2125,7 @@
   }
 
   void setValue(DataDescriptor descriptor, Object value) {
-    if (identical(descriptor, DartEntry.ANGULAR_ELEMENTS)) {
-      _angularElements = value as List<AngularElement>;
-      _angularElementsState = CacheState.VALID;
-    } else if (identical(descriptor, DartEntry.ELEMENT)) {
+    if (identical(descriptor, DartEntry.ELEMENT)) {
       _element = value as LibraryElement;
       _elementState = CacheState.VALID;
     } else if (identical(descriptor, DartEntry.EXPORTED_LIBRARIES)) {
@@ -2163,6 +2203,7 @@
     _exportedLibraries = other._exportedLibraries;
     _importedLibrariesState = other._importedLibrariesState;
     _importedLibraries = other._importedLibraries;
+    _containingLibraries = new List<Source>.from(other._containingLibraries);
     _resolutionState.copyFrom(other._resolutionState);
     _elementState = other._elementState;
     _element = other._element;
@@ -2170,12 +2211,10 @@
     _publicNamespace = other._publicNamespace;
     _clientServerState = other._clientServerState;
     _launchableState = other._launchableState;
-    _angularElementsState = other._angularElementsState;
-    _angularElements = other._angularElements;
     _bitmask = other._bitmask;
   }
 
-  bool hasErrorState() => super.hasErrorState() || identical(_sourceKindState, CacheState.ERROR) || identical(_parsedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_importedLibrariesState, CacheState.ERROR) || identical(_exportedLibrariesState, CacheState.ERROR) || identical(_includedPartsState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_angularElementsState, CacheState.ERROR) || identical(_publicNamespaceState, CacheState.ERROR) || identical(_clientServerState, CacheState.ERROR) || identical(_launchableState, CacheState.ERROR) || _resolutionState.hasErrorState();
+  bool hasErrorState() => super.hasErrorState() || identical(_sourceKindState, CacheState.ERROR) || identical(_parsedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_importedLibrariesState, CacheState.ERROR) || identical(_exportedLibrariesState, CacheState.ERROR) || identical(_includedPartsState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_publicNamespaceState, CacheState.ERROR) || identical(_clientServerState, CacheState.ERROR) || identical(_launchableState, CacheState.ERROR) || _resolutionState.hasErrorState();
 
   void writeOn(JavaStringBuilder builder) {
     builder.append("Dart: ");
@@ -2203,7 +2242,6 @@
     builder.append("; launchable = ");
     builder.append(_launchableState);
     builder.append("; angularElements = ");
-    builder.append(_angularElementsState);
     _resolutionState.writeOn(builder);
   }
 
@@ -2211,8 +2249,6 @@
    * Invalidate all of the resolution information associated with the compilation unit.
    */
   void discardCachedResolutionInformation() {
-    _angularElements = AngularElement.EMPTY_ARRAY;
-    _angularElementsState = CacheState.INVALID;
     _element = null;
     _elementState = CacheState.INVALID;
     _includedParts = Source.EMPTY_ARRAY;
@@ -2483,6 +2519,24 @@
  */
 abstract class HtmlEntry implements SourceEntry {
   /**
+   * The data descriptor representing the information about an Angular application this source is
+   * used in.
+   */
+  static final DataDescriptor<AngularApplicationInfo> ANGULAR_APPLICATION = new DataDescriptor<AngularApplicationInfo>("HtmlEntry.ANGULAR_APPLICATION");
+
+  /**
+   * The data descriptor representing the information about an Angular component this source is used
+   * as template for.
+   */
+  static final DataDescriptor<AngularComponentElement> ANGULAR_COMPONENT = new DataDescriptor<AngularComponentElement>("HtmlEntry.ANGULAR_COMPONENT");
+
+  /**
+   * The data descriptor representing the information about an Angular application this source is
+   * entry point for.
+   */
+  static final DataDescriptor<AngularApplicationInfo> ANGULAR_ENTRY = new DataDescriptor<AngularApplicationInfo>("HtmlEntry.ANGULAR_ENTRY");
+
+  /**
    * The data descriptor representing the errors reported during Angular resolution.
    */
   static final DataDescriptor<List<AnalysisError>> ANGULAR_ERRORS = new DataDescriptor<List<AnalysisError>>("HtmlEntry.ANGULAR_ERRORS");
@@ -2508,6 +2562,11 @@
   static final DataDescriptor<ht.HtmlUnit> PARSED_UNIT = new DataDescriptor<ht.HtmlUnit>("HtmlEntry.PARSED_UNIT");
 
   /**
+   * The data descriptor representing the resolved AST structure.
+   */
+  static final DataDescriptor<ht.HtmlUnit> RESOLVED_UNIT = new DataDescriptor<ht.HtmlUnit>("HtmlEntry.RESOLVED_UNIT");
+
+  /**
    * The data descriptor representing the list of referenced libraries.
    */
   static final DataDescriptor<List<Source>> REFERENCED_LIBRARIES = new DataDescriptor<List<Source>>("HtmlEntry.REFERENCED_LIBRARIES");
@@ -2524,6 +2583,14 @@
    */
   List<AnalysisError> get allErrors;
 
+  /**
+   * Return a valid parsed unit, either an unresolved AST structure or the result of resolving the
+   * AST structure, or `null` if there is no parsed unit available.
+   *
+   * @return a valid parsed unit
+   */
+  ht.HtmlUnit get anyParsedUnit;
+
   HtmlEntryImpl get writableCopy;
 }
 
@@ -2544,6 +2611,16 @@
   ht.HtmlUnit _parsedUnit;
 
   /**
+   * The state of the cached resolved HTML unit.
+   */
+  CacheState _resolvedUnitState = CacheState.INVALID;
+
+  /**
+   * The resolved HTML unit, or `null` if the resolved HTML unit is not currently cached.
+   */
+  ht.HtmlUnit _resolvedUnit;
+
+  /**
    * The state of the cached parse errors.
    */
   CacheState _parseErrorsState = CacheState.INVALID;
@@ -2587,6 +2664,36 @@
   HtmlElement _element;
 
   /**
+   * The state of the [angularApplication].
+   */
+  CacheState _angularApplicationState = CacheState.VALID;
+
+  /**
+   * Information about the Angular Application this unit is used in.
+   */
+  AngularApplicationInfo _angularApplication;
+
+  /**
+   * The state of the [angularEntry].
+   */
+  CacheState _angularEntryState = CacheState.VALID;
+
+  /**
+   * Information about the Angular Application this unit is entry point for.
+   */
+  AngularApplicationInfo _angularEntry = null;
+
+  /**
+   * The state of the [angularComponent].
+   */
+  CacheState _angularComponentState = CacheState.VALID;
+
+  /**
+   * Information about the [AngularComponentElement] this unit is used as template for.
+   */
+  AngularComponentElement _angularComponent = null;
+
+  /**
    * The state of the Angular resolution errors.
    */
   CacheState _angularErrorsState = CacheState.INVALID;
@@ -2608,6 +2715,20 @@
    */
   List<AnalysisError> _hints = AnalysisError.NO_ERRORS;
 
+  /**
+   * Flush any AST structures being maintained by this entry.
+   */
+  void flushAstStructures() {
+    if (identical(_parsedUnitState, CacheState.VALID)) {
+      _parsedUnitState = CacheState.FLUSHED;
+      _parsedUnit = null;
+    }
+    if (identical(_resolvedUnitState, CacheState.VALID)) {
+      _resolvedUnitState = CacheState.FLUSHED;
+      _resolvedUnit = null;
+    }
+  }
+
   List<AnalysisError> get allErrors {
     List<AnalysisError> errors = new List<AnalysisError>();
     if (_parseErrors != null) {
@@ -2636,10 +2757,28 @@
     return new List.from(errors);
   }
 
+  ht.HtmlUnit get anyParsedUnit {
+    if (identical(_parsedUnitState, CacheState.VALID)) {
+      //      parsedUnitAccessed = true;
+      return _parsedUnit;
+    }
+    if (identical(_resolvedUnitState, CacheState.VALID)) {
+      //      resovledUnitAccessed = true;
+      return _resolvedUnit;
+    }
+    return null;
+  }
+
   SourceKind get kind => SourceKind.HTML;
 
   CacheState getState(DataDescriptor descriptor) {
-    if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
+    if (identical(descriptor, HtmlEntry.ANGULAR_APPLICATION)) {
+      return _angularApplicationState;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_COMPONENT)) {
+      return _angularComponentState;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_ENTRY)) {
+      return _angularEntryState;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
       return _angularErrorsState;
     } else if (identical(descriptor, HtmlEntry.ELEMENT)) {
       return _elementState;
@@ -2647,6 +2786,8 @@
       return _parseErrorsState;
     } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
       return _parsedUnitState;
+    } else if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+      return _resolvedUnitState;
     } else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
       return _referencedLibrariesState;
     } else if (identical(descriptor, HtmlEntry.RESOLUTION_ERRORS)) {
@@ -2658,7 +2799,13 @@
   }
 
   Object getValue(DataDescriptor descriptor) {
-    if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
+    if (identical(descriptor, HtmlEntry.ANGULAR_APPLICATION)) {
+      return _angularApplication;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_COMPONENT)) {
+      return _angularComponent;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_ENTRY)) {
+      return _angularEntry;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
       return _angularErrors;
     } else if (identical(descriptor, HtmlEntry.ELEMENT)) {
       return _element;
@@ -2666,6 +2813,8 @@
       return _parseErrors;
     } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
       return _parsedUnit;
+    } else if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+      return _resolvedUnit;
     } else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
       return _referencedLibraries;
     } else if (identical(descriptor, HtmlEntry.RESOLUTION_ERRORS)) {
@@ -2688,6 +2837,8 @@
     _parseErrorsState = CacheState.INVALID;
     _parsedUnit = null;
     _parsedUnitState = CacheState.INVALID;
+    _resolvedUnit = null;
+    _resolvedUnitState = CacheState.INVALID;
     _referencedLibraries = Source.EMPTY_ARRAY;
     _referencedLibrariesState = CacheState.INVALID;
     invalidateAllResolutionInformation();
@@ -2725,13 +2876,23 @@
    */
   void recordResolutionError() {
     setState(HtmlEntry.ANGULAR_ERRORS, CacheState.ERROR);
+    setState(HtmlEntry.RESOLVED_UNIT, CacheState.ERROR);
     setState(HtmlEntry.ELEMENT, CacheState.ERROR);
     setState(HtmlEntry.RESOLUTION_ERRORS, CacheState.ERROR);
     setState(HtmlEntry.HINTS, CacheState.ERROR);
   }
 
   void setState(DataDescriptor descriptor, CacheState state) {
-    if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
+    if (identical(descriptor, HtmlEntry.ANGULAR_APPLICATION)) {
+      _angularApplication = updatedValue(state, _angularApplication, null);
+      _angularApplicationState = state;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_COMPONENT)) {
+      _angularComponent = updatedValue(state, _angularComponent, null);
+      _angularComponentState = state;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_ENTRY)) {
+      _angularEntry = updatedValue(state, _angularEntry, null);
+      _angularEntryState = state;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
       _angularErrors = updatedValue(state, _angularErrors, null);
       _angularErrorsState = state;
     } else if (identical(descriptor, HtmlEntry.ELEMENT)) {
@@ -2743,6 +2904,9 @@
     } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
       _parsedUnit = updatedValue(state, _parsedUnit, null);
       _parsedUnitState = state;
+    } else if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+      _resolvedUnit = updatedValue(state, _resolvedUnit, null);
+      _resolvedUnitState = state;
     } else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
       _referencedLibraries = updatedValue(state, _referencedLibraries, Source.EMPTY_ARRAY);
       _referencedLibrariesState = state;
@@ -2758,7 +2922,16 @@
   }
 
   void setValue(DataDescriptor descriptor, Object value) {
-    if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
+    if (identical(descriptor, HtmlEntry.ANGULAR_APPLICATION)) {
+      _angularApplication = value as AngularApplicationInfo;
+      _angularApplicationState = CacheState.VALID;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_COMPONENT)) {
+      _angularComponent = value as AngularComponentElement;
+      _angularComponentState = CacheState.VALID;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_ENTRY)) {
+      _angularEntry = value as AngularApplicationInfo;
+      _angularEntryState = CacheState.VALID;
+    } else if (identical(descriptor, HtmlEntry.ANGULAR_ERRORS)) {
       _angularErrors = value as List<AnalysisError>;
       _angularErrorsState = CacheState.VALID;
     } else if (identical(descriptor, HtmlEntry.ELEMENT)) {
@@ -2770,6 +2943,9 @@
     } else if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
       _parsedUnit = value as ht.HtmlUnit;
       _parsedUnitState = CacheState.VALID;
+    } else if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+      _resolvedUnit = value as ht.HtmlUnit;
+      _resolvedUnitState = CacheState.VALID;
     } else if (identical(descriptor, HtmlEntry.REFERENCED_LIBRARIES)) {
       _referencedLibraries = value == null ? Source.EMPTY_ARRAY : (value as List<Source>);
       _referencedLibrariesState = CacheState.VALID;
@@ -2787,12 +2963,20 @@
   void copyFrom(SourceEntryImpl entry) {
     super.copyFrom(entry);
     HtmlEntryImpl other = entry as HtmlEntryImpl;
+    _angularApplicationState = other._angularApplicationState;
+    _angularApplication = other._angularApplication;
+    _angularComponentState = other._angularComponentState;
+    _angularComponent = other._angularComponent;
+    _angularEntryState = other._angularEntryState;
+    _angularEntry = other._angularEntry;
     _angularErrorsState = other._angularErrorsState;
     _angularErrors = other._angularErrors;
     _parseErrorsState = other._parseErrorsState;
     _parseErrors = other._parseErrors;
     _parsedUnitState = other._parsedUnitState;
     _parsedUnit = other._parsedUnit;
+    _resolvedUnitState = other._resolvedUnitState;
+    _resolvedUnit = other._resolvedUnit;
     _referencedLibrariesState = other._referencedLibrariesState;
     _referencedLibraries = other._referencedLibraries;
     _resolutionErrors = other._resolutionErrors;
@@ -2803,7 +2987,7 @@
     _hintsState = other._hintsState;
   }
 
-  bool hasErrorState() => super.hasErrorState() || identical(_parsedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_resolutionErrorsState, CacheState.ERROR) || identical(_referencedLibrariesState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_angularErrorsState, CacheState.ERROR) || identical(_hintsState, CacheState.ERROR);
+  bool hasErrorState() => super.hasErrorState() || identical(_parsedUnitState, CacheState.ERROR) || identical(_resolvedUnitState, CacheState.ERROR) || identical(_parseErrorsState, CacheState.ERROR) || identical(_resolutionErrorsState, CacheState.ERROR) || identical(_referencedLibrariesState, CacheState.ERROR) || identical(_elementState, CacheState.ERROR) || identical(_angularErrorsState, CacheState.ERROR) || identical(_hintsState, CacheState.ERROR);
 
   void writeOn(JavaStringBuilder builder) {
     builder.append("Html: ");
@@ -2812,12 +2996,20 @@
     builder.append(_parseErrorsState);
     builder.append("; parsedUnit = ");
     builder.append(_parsedUnitState);
+    builder.append("; resolvedUnit = ");
+    builder.append(_resolvedUnitState);
     builder.append("; resolutionErrors = ");
     builder.append(_resolutionErrorsState);
     builder.append("; referencedLibraries = ");
     builder.append(_referencedLibrariesState);
     builder.append("; element = ");
     builder.append(_elementState);
+    builder.append("; angularApplication = ");
+    builder.append(_angularApplicationState);
+    builder.append("; angularComponent = ");
+    builder.append(_angularComponentState);
+    builder.append("; angularEntry = ");
+    builder.append(_angularEntryState);
     builder.append("; angularErrors = ");
     builder.append(_angularErrorsState);
   }
@@ -3246,6 +3438,11 @@
   IncrementalAnalysisCache _incrementalAnalysisCache;
 
   /**
+   * The object used to manage the list of sources that need to be analyzed.
+   */
+  WorkManager _workManager = new WorkManager();
+
+  /**
    * Initialize a newly created analysis context.
    */
   AnalysisContextImpl() : super() {
@@ -3294,11 +3491,22 @@
         // only re-analyze those libraries.
         logInformation("Added Dart sources, invalidating all resolution information");
         for (MapEntry<Source, SourceEntry> mapEntry in _cache.entrySet()) {
+          Source source = mapEntry.getKey();
           SourceEntry sourceEntry = mapEntry.getValue();
-          if (!mapEntry.getKey().isInSystemLibrary && sourceEntry is DartEntry) {
-            DartEntryImpl dartCopy = sourceEntry.writableCopy;
+          if (!source.isInSystemLibrary && sourceEntry is DartEntry) {
+            DartEntry dartEntry = sourceEntry;
+            DartEntryImpl dartCopy = dartEntry.writableCopy;
+            removeFromParts(source, dartEntry);
             dartCopy.invalidateAllResolutionInformation();
             mapEntry.setValue(dartCopy);
+            SourcePriority priority = SourcePriority.UNKNOWN;
+            SourceKind kind = dartCopy.kind;
+            if (identical(kind, SourceKind.LIBRARY)) {
+              priority = SourcePriority.LIBRARY;
+            } else if (identical(kind, SourceKind.PART)) {
+              priority = SourcePriority.NORMAL_PART;
+            }
+            _workManager.add(source, priority);
           }
         }
       }
@@ -3407,29 +3615,35 @@
     return null;
   }
 
+  ResolvableHtmlUnit computeResolvableAngularComponentHtmlUnit(Source source) {
+    HtmlEntry htmlEntry = getReadableHtmlEntry(source);
+    if (htmlEntry == null) {
+      throw new AnalysisException.con1("computeResolvableAngularComponentHtmlUnit invoked for non-HTML file: ${source.fullName}");
+    }
+    htmlEntry = cacheHtmlResolutionData(source, htmlEntry, HtmlEntry.RESOLVED_UNIT);
+    ht.HtmlUnit unit = htmlEntry.getValue(HtmlEntry.RESOLVED_UNIT);
+    if (unit == null) {
+      AnalysisException cause = htmlEntry.exception;
+      throw new AnalysisException.con2("Internal error: computeResolvableAngularComponentHtmlUnit could not resolve ${source.fullName}", cause);
+    }
+    // If the unit is ever modified by resolution then we will need to create a copy of it.
+    return new ResolvableHtmlUnit(htmlEntry.modificationTime, unit);
+  }
+
   ResolvableCompilationUnit computeResolvableCompilationUnit(Source source) {
-    while (true) {
-      {
-        DartEntry dartEntry = getReadableDartEntry(source);
-        if (dartEntry == null) {
-          throw new AnalysisException.con1("computeResolvableCompilationUnit for non-Dart: ${source.fullName}");
-        }
-        if (identical(dartEntry.getState(DartEntry.PARSED_UNIT), CacheState.ERROR)) {
-          AnalysisException cause = dartEntry.exception;
-          if (cause == null) {
-            throw new AnalysisException.con1("Internal error: computeResolvableCompilationUnit could not parse ${source.fullName}");
-          } else {
-            throw new AnalysisException.con2("Internal error: computeResolvableCompilationUnit could not parse ${source.fullName}", cause);
-          }
-        }
-        DartEntryImpl dartCopy = dartEntry.writableCopy;
-        CompilationUnit unit = dartCopy.resolvableCompilationUnit;
-        if (unit != null) {
-          _cache.put(source, dartCopy);
-          return new ResolvableCompilationUnit(dartCopy.modificationTime, unit);
-        }
+    {
+      DartEntry dartEntry = getReadableDartEntry(source);
+      if (dartEntry == null) {
+        throw new AnalysisException.con1("computeResolvableCompilationUnit for non-Dart: ${source.fullName}");
       }
-      cacheDartParseData(source, getReadableDartEntry(source), DartEntry.PARSED_UNIT);
+      dartEntry = cacheDartParseData(source, dartEntry, DartEntry.PARSED_UNIT);
+      DartEntryImpl dartCopy = dartEntry.writableCopy;
+      CompilationUnit unit = dartCopy.resolvableCompilationUnit;
+      if (unit == null) {
+        throw new AnalysisException.con2("Internal error: computeResolvableCompilationUnit could not parse ${source.fullName}", dartEntry.exception);
+      }
+      _cache.put(source, dartCopy);
+      return new ResolvableCompilationUnit(dartCopy.modificationTime, unit);
     }
   }
 
@@ -3581,25 +3795,11 @@
   }
 
   List<Source> getLibrariesContaining(Source source) {
-    {
-      SourceEntry sourceEntry = _cache.get(source);
-      if (sourceEntry == null || sourceEntry.kind != SourceKind.PART) {
-        return <Source> [source];
-      }
-      List<Source> librarySources = new List<Source>();
-      for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
-        sourceEntry = entry.getValue();
-        if (identical(sourceEntry.kind, SourceKind.LIBRARY)) {
-          if (contains((sourceEntry as DartEntry).getValue(DartEntry.INCLUDED_PARTS), source)) {
-            librarySources.add(entry.getKey());
-          }
-        }
-      }
-      if (librarySources.isEmpty) {
-        return Source.EMPTY_ARRAY;
-      }
-      return new List.from(librarySources);
+    DartEntry dartEntry = getReadableDartEntry(source);
+    if (dartEntry == null) {
+      return Source.EMPTY_ARRAY;
     }
+    return dartEntry.getValue(DartEntry.CONTAINING_LIBRARIES);
   }
 
   List<Source> getLibrariesDependingOn(Source librarySource) {
@@ -3623,14 +3823,6 @@
     }
   }
 
-  List<AngularElement> getLibraryAngularElements(Source source) {
-    SourceEntry sourceEntry = getReadableSourceEntry(source);
-    if (sourceEntry is DartEntry) {
-      return sourceEntry.getValue(DartEntry.ANGULAR_ELEMENTS);
-    }
-    return AngularElement.EMPTY_ARRAY;
-  }
-
   LibraryElement getLibraryElement(Source source) {
     SourceEntry sourceEntry = getReadableSourceEntry(source);
     if (sourceEntry is DartEntry) {
@@ -3667,7 +3859,7 @@
       {
         dartEntry = getReadableDartEntry(source);
         if (dartEntry == null) {
-          AnalysisEngine.instance.logger.logError3(new AnalysisException.con1("A Dart file became a non-Dart file: ${source.fullName}"));
+          AnalysisEngine.instance.logger.logError2("Could not compute the public namespace for ${library.source.fullName}", new AnalysisException.con1("A Dart file became a non-Dart file: ${source.fullName}"));
           return null;
         }
         if (identical(dartEntry.getValue(DartEntry.ELEMENT), library)) {
@@ -3744,9 +3936,7 @@
     SourceEntry sourceEntry = getReadableSourceEntry(htmlSource);
     if (sourceEntry is HtmlEntry) {
       HtmlEntry htmlEntry = sourceEntry;
-      if (htmlEntry.getValue(HtmlEntry.ELEMENT) != null) {
-        return htmlEntry.getValue(HtmlEntry.PARSED_UNIT);
-      }
+      return htmlEntry.getValue(HtmlEntry.RESOLVED_UNIT);
     }
     return null;
   }
@@ -3755,7 +3945,7 @@
 
   /**
    * Return a list of the sources that would be processed by [performAnalysisTask]. This
-   * method duplicates, and must therefore be kept in sync with, [getNextTaskAnalysisTask].
+   * method duplicates, and must therefore be kept in sync with, [getNextAnalysisTask].
    * This method is intended to be used for testing purposes only.
    *
    * @return a list of the sources that would be processed by [performAnalysisTask]
@@ -3876,10 +4066,10 @@
 
   AnalysisResult performAnalysisTask() {
     int getStart = JavaSystem.currentTimeMillis();
-    AnalysisTask task = nextTaskAnalysisTask;
+    AnalysisTask task = nextAnalysisTask;
     int getEnd = JavaSystem.currentTimeMillis();
     if (task == null && validateCacheConsistency()) {
-      task = nextTaskAnalysisTask;
+      task = nextAnalysisTask;
     }
     if (task == null) {
       return new AnalysisResult(getChangeNotices(true), getEnd - getStart, null, -1);
@@ -3914,7 +4104,7 @@
         DartEntry dartEntry = getReadableDartEntry(librarySource);
         if (dartEntry != null) {
           DartEntryImpl dartCopy = dartEntry.writableCopy;
-          recordElementData(dartCopy, library, htmlSource);
+          recordElementData(dartEntry, dartCopy, library, library.source, htmlSource);
           _cache.put(librarySource, dartCopy);
         }
       }
@@ -4080,6 +4270,7 @@
         dartCopy.recordResolutionError();
         dartCopy.exception = thrownException;
         _cache.put(unitSource, dartCopy);
+        _cache.remove(unitSource);
         if (thrownException != null) {
           throw thrownException;
         }
@@ -4111,15 +4302,19 @@
                 dartCopy.setState(DartEntry.PARSED_UNIT, CacheState.FLUSHED);
                 dartCopy.setValue2(DartEntry.RESOLVED_UNIT, librarySource, unit);
                 dartCopy.setValue2(DartEntry.RESOLUTION_ERRORS, librarySource, errors);
-                if (identical(source, librarySource)) {
-                  recordElementData(dartCopy, library.libraryElement, htmlSource);
-                  recordAngularComponents(library, dartCopy);
+                if (source == librarySource) {
+                  recordElementData(dartEntry, dartCopy, library.libraryElement, librarySource, htmlSource);
                 }
+                _cache.storedAst(source);
               } else {
                 dartCopy.recordResolutionError();
+                _cache.remove(source);
               }
               dartCopy.exception = thrownException;
               _cache.put(source, dartCopy);
+              if (source != librarySource) {
+                _workManager.add(source, SourcePriority.PRIORITY_PART);
+              }
               if (source == unitSource) {
                 unitEntry = dartCopy;
               }
@@ -4151,6 +4346,7 @@
                   // good chance that we'll be able to do so without error.
                   //
                   dartCopy.recordResolutionError();
+                  _cache.remove(source);
                 }
                 dartCopy.exception = thrownException;
                 _cache.put(source, dartCopy);
@@ -4179,6 +4375,18 @@
   }
 
   /**
+   * Record that we have accessed the AST structure associated with the given source. At the moment,
+   * there is no differentiation between the parsed and resolved forms of the AST.
+   *
+   * @param source the source whose AST structure was accessed
+   */
+  void accessedAst(Source source) {
+    {
+      _cache.accessedAst(source);
+    }
+  }
+
+  /**
    * Add all of the sources contained in the given source container to the given list of sources.
    *
    * Note: This method must only be invoked while we are synchronized on [cacheLock].
@@ -4227,9 +4435,10 @@
   }
 
   /**
-   * Given a source for a Dart file, return a cache entry in which the data represented by the given
-   * descriptor is available. This method assumes that the data can be produced by resolving the
-   * directives in the source if they are not already cached.
+   * Given a source for a Dart file, return a cache entry in which the state of the data represented
+   * by the given descriptor is either [CacheState#VALID] or [CacheState#ERROR]. This
+   * method assumes that the data can be produced by resolving the directives in the source if they
+   * are not already cached.
    *
    * @param source the source representing the Dart file
    * @param dartEntry the cache entry associated with the Dart file
@@ -4256,8 +4465,9 @@
 
   /**
    * Given a source for a Dart file and the library that contains it, return a cache entry in which
-   * the data represented by the given descriptor is available. This method assumes that the data
-   * can be produced by generating hints for the library if the data is not already cached.
+   * the state of the data represented by the given descriptor is either [CacheState#VALID] or
+   * [CacheState#ERROR]. This method assumes that the data can be produced by generating hints
+   * for the library if the data is not already cached.
    *
    * @param unitSource the source representing the Dart file
    * @param librarySource the source representing the library containing the Dart file
@@ -4283,9 +4493,9 @@
   }
 
   /**
-   * Given a source for a Dart file, return a cache entry in which the data represented by the given
-   * descriptor is available. This method assumes that the data can be produced by parsing the
-   * source if it is not already cached.
+   * Given a source for a Dart file, return a cache entry in which the state of the data represented
+   * by the given descriptor is either [CacheState#VALID] or [CacheState#ERROR]. This
+   * method assumes that the data can be produced by parsing the source if it is not already cached.
    *
    * @param source the source representing the Dart file
    * @param dartEntry the cache entry associated with the Dart file
@@ -4318,9 +4528,9 @@
 
   /**
    * Given a source for a Dart file and the library that contains it, return a cache entry in which
-   * the data represented by the given descriptor is available. This method assumes that the data
-   * can be produced by resolving the source in the context of the library if it is not already
-   * cached.
+   * the state of the data represented by the given descriptor is either [CacheState#VALID] or
+   * [CacheState#ERROR]. This method assumes that the data can be produced by resolving the
+   * source in the context of the library if it is not already cached.
    *
    * @param unitSource the source representing the Dart file
    * @param librarySource the source representing the library containing the Dart file
@@ -4349,8 +4559,9 @@
 
   /**
    * Given a source for a Dart file and the library that contains it, return a cache entry in which
-   * the data represented by the given descriptor is available. This method assumes that the data
-   * can be produced by verifying the source in the given library if the data is not already cached.
+   * the state of the data represented by the given descriptor is either [CacheState#VALID] or
+   * [CacheState#ERROR]. This method assumes that the data can be produced by verifying the
+   * source in the given library if the data is not already cached.
    *
    * @param unitSource the source representing the Dart file
    * @param librarySource the source representing the library containing the Dart file
@@ -4377,8 +4588,9 @@
 
   /**
    * Given a source for an HTML file, return a cache entry in which all of the data represented by
-   * the given descriptors is available. This method assumes that the data can be produced by
-   * parsing the source if it is not already cached.
+   * the state of the given descriptors is either [CacheState#VALID] or
+   * [CacheState#ERROR]. This method assumes that the data can be produced by parsing the
+   * source if it is not already cached.
    *
    * @param source the source representing the HTML file
    * @param htmlEntry the cache entry associated with the HTML file
@@ -4388,6 +4600,12 @@
    *           resolved
    */
   HtmlEntry cacheHtmlParseData(Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) {
+    if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
+      ht.HtmlUnit unit = htmlEntry.anyParsedUnit;
+      if (unit != null) {
+        return htmlEntry;
+      }
+    }
     //
     // Check to see whether we already have the information being requested.
     //
@@ -4404,9 +4622,10 @@
   }
 
   /**
-   * Given a source for an HTML file, return a cache entry in which the the data represented by the
-   * given descriptor is available. This method assumes that the data can be produced by resolving
-   * the source if it is not already cached.
+   * Given a source for an HTML file, return a cache entry in which the state of the data
+   * represented by the given descriptor is either [CacheState#VALID] or
+   * [CacheState#ERROR]. This method assumes that the data can be produced by resolving the
+   * source if it is not already cached.
    *
    * @param source the source representing the HTML file
    * @param dartEntry the cache entry associated with the HTML file
@@ -4599,6 +4818,7 @@
   Object getDartParseData(Source source, DartEntry dartEntry, DataDescriptor descriptor) {
     dartEntry = cacheDartParseData(source, dartEntry, descriptor);
     if (identical(descriptor, DartEntry.PARSED_UNIT)) {
+      accessedAst(source);
       return dartEntry.anyParsedCompilationUnit;
     }
     return dartEntry.getValue(descriptor);
@@ -4640,6 +4860,8 @@
     dartEntry = cacheDartResolutionData(unitSource, librarySource, dartEntry, descriptor);
     if (identical(descriptor, DartEntry.ELEMENT)) {
       return dartEntry.getValue(descriptor);
+    } else if (identical(descriptor, DartEntry.RESOLVED_UNIT)) {
+      accessedAst(unitSource);
     }
     return dartEntry.getValue2(descriptor, librarySource);
   }
@@ -4701,6 +4923,10 @@
       return defaultValue;
     }
     htmlEntry = cacheHtmlParseData(source, htmlEntry, descriptor);
+    if (identical(descriptor, HtmlEntry.PARSED_UNIT)) {
+      accessedAst(source);
+      return htmlEntry.anyParsedUnit;
+    }
     return htmlEntry.getValue(descriptor);
   }
 
@@ -4739,6 +4965,9 @@
    */
   Object getHtmlResolutionData2(Source source, HtmlEntry htmlEntry, DataDescriptor descriptor) {
     htmlEntry = cacheHtmlResolutionData(source, htmlEntry, descriptor);
+    if (identical(descriptor, HtmlEntry.RESOLVED_UNIT)) {
+      accessedAst(source);
+    }
     return htmlEntry.getValue(descriptor);
   }
 
@@ -4748,7 +4977,7 @@
    *
    * @return the next task that needs to be performed
    */
-  AnalysisTask get nextTaskAnalysisTask {
+  AnalysisTask get nextAnalysisTask {
     {
       bool hintsEnabled = _options.hint;
       //
@@ -4763,7 +4992,7 @@
       // Look for a priority source that needs to be analyzed.
       //
       for (Source source in _priorityOrder) {
-        AnalysisTask task = getNextTaskAnalysisTask2(source, _cache.get(source), true, hintsEnabled);
+        AnalysisTask task = getNextAnalysisTask2(source, _cache.get(source), true, hintsEnabled);
         if (task != null) {
           return task;
         }
@@ -4771,49 +5000,26 @@
       //
       // Look for a non-priority source that needs to be analyzed.
       //
-      for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
-        AnalysisTask task = getNextTaskAnalysisTask2(entry.getKey(), entry.getValue(), false, hintsEnabled);
+      Source source = _workManager.nextSource;
+      while (source != null) {
+        AnalysisTask task = getNextAnalysisTask2(source, _cache.get(source), false, hintsEnabled);
         if (task != null) {
           return task;
         }
+        _workManager.remove(source);
+        source = _workManager.nextSource;
       }
-      //
-      // Look for HTML sources that should be resolved as Angular templates.
-      //
-      for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
-        SourceEntry sourceEntry = entry.getValue();
-        if (sourceEntry is DartEntry) {
-          DartEntry dartEntry = sourceEntry;
-          List<AngularElement> angularElements = dartEntry.getValue(DartEntry.ANGULAR_ELEMENTS);
-          for (AngularElement angularElement in angularElements) {
-            // prepare Angular component
-            if (angularElement is! AngularComponentElement) {
-              continue;
-            }
-            AngularComponentElement component = angularElement as AngularComponentElement;
-            // prepare HTML template
-            Source templateSource = component.templateSource;
-            if (templateSource == null) {
-              continue;
-            }
-            // prepare HTML template entry
-            HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
-            if (htmlEntry == null) {
-              continue;
-            }
-            // we need an entry with invalid Angular errors
-            CacheState angularErrorsState = htmlEntry.getState(HtmlEntry.ANGULAR_ERRORS);
-            if (angularErrorsState != CacheState.INVALID) {
-              continue;
-            }
-            // do Angular component resolution
-            HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
-            htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.IN_PROCESS);
-            _cache.put(templateSource, htmlCopy);
-            return new ResolveAngularComponentTemplateTask(this, templateSource, component, angularElements);
-          }
-        }
-      }
+      //      //
+      //      // Look for a non-priority source that needs to be analyzed and was missed by the loop above.
+      //      //
+      //      for (Map.Entry<Source, SourceEntry> entry : cache.entrySet()) {
+      //        source = entry.getKey();
+      //        AnalysisTask task = getNextAnalysisTask(source, entry.getValue(), false, hintsEnabled);
+      //        if (task != null) {
+      //          System.out.println("Failed to analyze " + source.getFullName());
+      //          return task;
+      //        }
+      //      }
       return null;
     }
   }
@@ -4831,16 +5037,9 @@
    * @param hintsEnabled `true` if hints are currently enabled
    * @return the next task that needs to be performed for the given source
    */
-  AnalysisTask getNextTaskAnalysisTask2(Source source, SourceEntry sourceEntry, bool isPriority, bool hintsEnabled) {
+  AnalysisTask getNextAnalysisTask2(Source source, SourceEntry sourceEntry, bool isPriority, bool hintsEnabled) {
     if (sourceEntry is DartEntry) {
       DartEntry dartEntry = sourceEntry;
-      if (!source.exists()) {
-        DartEntryImpl dartCopy = dartEntry.writableCopy;
-        dartCopy.recordParseError();
-        dartCopy.exception = new AnalysisException.con1("Source does not exist");
-        _cache.put(source, dartCopy);
-        return null;
-      }
       CacheState parseErrorsState = dartEntry.getState(DartEntry.PARSE_ERRORS);
       if (identical(parseErrorsState, CacheState.INVALID) || (isPriority && identical(parseErrorsState, CacheState.FLUSHED))) {
         DartEntryImpl dartCopy = dartEntry.writableCopy;
@@ -4864,7 +5063,8 @@
         _cache.put(source, dartCopy);
         return new ResolveDartDependenciesTask(this, source);
       }
-      for (Source librarySource in getLibrariesContaining(source)) {
+      List<Source> librariesContaining = dartEntry.getValue(DartEntry.CONTAINING_LIBRARIES);
+      for (Source librarySource in librariesContaining) {
         SourceEntry libraryEntry = _cache.get(librarySource);
         if (libraryEntry is DartEntry) {
           CacheState elementState = libraryEntry.getState(DartEntry.ELEMENT);
@@ -4915,27 +5115,52 @@
       }
     } else if (sourceEntry is HtmlEntry) {
       HtmlEntry htmlEntry = sourceEntry;
-      if (!source.exists()) {
-        HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
-        htmlCopy.recordParseError();
-        htmlCopy.exception = new AnalysisException.con1("Source does not exist");
-        _cache.put(source, htmlCopy);
-        return null;
-      }
-      CacheState parsedUnitState = htmlEntry.getState(HtmlEntry.PARSED_UNIT);
-      if (identical(parsedUnitState, CacheState.INVALID) || (isPriority && identical(parsedUnitState, CacheState.FLUSHED))) {
-        HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
-        htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.IN_PROCESS);
-        _cache.put(source, htmlCopy);
+      CacheState parseErrorsState = htmlEntry.getState(HtmlEntry.PARSE_ERRORS);
+      if (identical(parseErrorsState, CacheState.INVALID) || (isPriority && identical(parseErrorsState, CacheState.FLUSHED))) {
+        HtmlEntryImpl dartCopy = htmlEntry.writableCopy;
+        dartCopy.setState(HtmlEntry.PARSE_ERRORS, CacheState.IN_PROCESS);
+        _cache.put(source, dartCopy);
         return new ParseHtmlTask(this, source);
       }
-      CacheState elementState = htmlEntry.getState(HtmlEntry.ELEMENT);
-      if (identical(elementState, CacheState.INVALID) || (isPriority && identical(elementState, CacheState.FLUSHED))) {
+      if (isPriority && parseErrorsState != CacheState.ERROR) {
+        ht.HtmlUnit parsedUnit = htmlEntry.anyParsedUnit;
+        if (parsedUnit == null) {
+          HtmlEntryImpl dartCopy = htmlEntry.writableCopy;
+          dartCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.IN_PROCESS);
+          _cache.put(source, dartCopy);
+          return new ParseHtmlTask(this, source);
+        }
+      }
+      CacheState resolvedUnitState = htmlEntry.getState(HtmlEntry.RESOLVED_UNIT);
+      if (identical(resolvedUnitState, CacheState.INVALID) || (isPriority && identical(resolvedUnitState, CacheState.FLUSHED))) {
         HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
-        htmlCopy.setState(HtmlEntry.ELEMENT, CacheState.IN_PROCESS);
+        htmlCopy.setState(HtmlEntry.RESOLVED_UNIT, CacheState.IN_PROCESS);
         _cache.put(source, htmlCopy);
         return new ResolveHtmlTask(this, source);
       }
+      CacheState angularErrorsState = htmlEntry.getState(HtmlEntry.ANGULAR_ERRORS);
+      if (identical(angularErrorsState, CacheState.INVALID)) {
+        AngularApplicationInfo entryInfo = htmlEntry.getValue(HtmlEntry.ANGULAR_ENTRY);
+        if (entryInfo != null) {
+          HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+          htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.IN_PROCESS);
+          _cache.put(source, htmlCopy);
+          return new ResolveAngularEntryHtmlTask(this, source, entryInfo);
+        }
+        AngularApplicationInfo applicationInfo = htmlEntry.getValue(HtmlEntry.ANGULAR_APPLICATION);
+        if (applicationInfo != null) {
+          AngularComponentElement component = htmlEntry.getValue(HtmlEntry.ANGULAR_COMPONENT);
+          if (component != null) {
+            HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+            htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.IN_PROCESS);
+            _cache.put(source, htmlCopy);
+            return new ResolveAngularComponentTemplateTask(this, source, component, applicationInfo);
+          }
+        }
+        HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+        htmlCopy.setValue(HtmlEntry.ANGULAR_ERRORS, AnalysisError.NO_ERRORS);
+        _cache.put(source, htmlCopy);
+      }
     }
     return null;
   }
@@ -4969,7 +5194,6 @@
         sourceEntry = createSourceEntry(source);
       }
       if (sourceEntry is DartEntry) {
-        _cache.accessed(source);
         return sourceEntry as DartEntry;
       }
       return null;
@@ -4990,7 +5214,6 @@
         sourceEntry = createSourceEntry(source);
       }
       if (sourceEntry is HtmlEntry) {
-        _cache.accessed(source);
         return sourceEntry as HtmlEntry;
       }
       return null;
@@ -5010,9 +5233,6 @@
       if (sourceEntry == null) {
         sourceEntry = createSourceEntry(source);
       }
-      if (sourceEntry != null) {
-        _cache.accessed(source);
-      }
       return sourceEntry;
     }
   }
@@ -5039,8 +5259,8 @@
    * Look at the given source to see whether a task needs to be performed related to it. If so, add
    * the source to the set of sources that need to be processed. This method duplicates, and must
    * therefore be kept in sync with,
-   * [getNextTaskAnalysisTask]. This method is
-   * intended to be used for testing purposes only.
+   * [getNextAnalysisTask]. This method is intended to
+   * be used for testing purposes only.
    *
    * <b>Note:</b> This method must only be invoked while we are synchronized on [cacheLock].
    *
@@ -5108,11 +5328,27 @@
         sources.add(source);
         return;
       }
-      CacheState elementState = htmlEntry.getState(HtmlEntry.ELEMENT);
-      if (identical(elementState, CacheState.INVALID) || (isPriority && identical(elementState, CacheState.FLUSHED))) {
+      CacheState resolvedUnitState = htmlEntry.getState(HtmlEntry.RESOLVED_UNIT);
+      if (identical(resolvedUnitState, CacheState.INVALID) || (isPriority && identical(resolvedUnitState, CacheState.FLUSHED))) {
         sources.add(source);
         return;
       }
+      CacheState angularErrorsState = htmlEntry.getState(HtmlEntry.ANGULAR_ERRORS);
+      if (identical(angularErrorsState, CacheState.INVALID)) {
+        AngularApplicationInfo entryInfo = htmlEntry.getValue(HtmlEntry.ANGULAR_ENTRY);
+        if (entryInfo != null) {
+          sources.add(source);
+          return;
+        }
+        AngularApplicationInfo applicationInfo = htmlEntry.getValue(HtmlEntry.ANGULAR_APPLICATION);
+        if (applicationInfo != null) {
+          AngularComponentElement component = htmlEntry.getValue(HtmlEntry.ANGULAR_COMPONENT);
+          if (component != null) {
+            sources.add(source);
+            return;
+          }
+        }
+      }
     }
   }
 
@@ -5123,15 +5359,19 @@
    */
   void invalidateAllResolutionInformation() {
     for (MapEntry<Source, SourceEntry> mapEntry in _cache.entrySet()) {
+      Source source = mapEntry.getKey();
       SourceEntry sourceEntry = mapEntry.getValue();
       if (sourceEntry is HtmlEntry) {
         HtmlEntryImpl htmlCopy = sourceEntry.writableCopy;
         htmlCopy.invalidateAllResolutionInformation();
         mapEntry.setValue(htmlCopy);
       } else if (sourceEntry is DartEntry) {
-        DartEntryImpl dartCopy = sourceEntry.writableCopy;
+        DartEntry dartEntry = sourceEntry;
+        removeFromParts(source, dartEntry);
+        DartEntryImpl dartCopy = dartEntry.writableCopy;
         dartCopy.invalidateAllResolutionInformation();
         mapEntry.setValue(dartCopy);
+        _workManager.add(source, SourcePriority.UNKNOWN);
       }
     }
   }
@@ -5142,6 +5382,9 @@
    *
    * <b>Note:</b> This method must only be invoked while we are synchronized on [cacheLock].
    *
+   * <b>Note:</b> Any cache entries that were accessed before this method was invoked must be
+   * re-accessed after this method returns.
+   *
    * @param librarySource the source of the library being invalidated
    * @param writer the writer to which debugging information should be written
    */
@@ -5155,8 +5398,8 @@
       DartEntryImpl libraryCopy = libraryEntry.writableCopy;
       int oldTime = libraryCopy.modificationTime;
       libraryCopy.invalidateAllResolutionInformation();
-      libraryCopy.setState(DartEntry.INCLUDED_PARTS, CacheState.INVALID);
       _cache.put(librarySource, libraryCopy);
+      _workManager.add(librarySource, SourcePriority.LIBRARY);
       if (writer != null) {
         writer.println("  Invalidated library source: ${debuggingString(librarySource)} (previously modified at ${oldTime})");
       }
@@ -5165,6 +5408,10 @@
         if (partEntry is DartEntry) {
           DartEntryImpl partCopy = partEntry.writableCopy;
           oldTime = partCopy.modificationTime;
+          if (partEntry != libraryCopy) {
+            partCopy.removeContainingLibrary(librarySource);
+            _workManager.add(librarySource, SourcePriority.NORMAL_PART);
+          }
           partCopy.invalidateAllResolutionInformation();
           _cache.put(partSource, partCopy);
           if (writer != null) {
@@ -5233,10 +5480,11 @@
    * @param library the [Library] that was resolved
    * @param dartCopy the [DartEntryImpl] to record new Angular components
    */
-  void recordAngularComponents(Library library, DartEntryImpl dartCopy) {
+  void recordAngularComponents(HtmlEntryImpl entry, AngularApplicationInfo app) {
     // reset old Angular errors
-    List<AngularElement> oldAngularElements = dartCopy.getValue(DartEntry.ANGULAR_ELEMENTS);
-    if (oldAngularElements != null) {
+    AngularApplicationInfo oldApp = entry.getValue(HtmlEntry.ANGULAR_ENTRY);
+    if (oldApp != null) {
+      List<AngularElement> oldAngularElements = oldApp.elements;
       for (AngularElement angularElement in oldAngularElements) {
         if (angularElement is AngularComponentElement) {
           AngularComponentElement component = angularElement;
@@ -5244,6 +5492,8 @@
           if (templateSource != null) {
             HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
             HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+            htmlCopy.setValue(HtmlEntry.ANGULAR_APPLICATION, null);
+            htmlCopy.setValue(HtmlEntry.ANGULAR_COMPONENT, null);
             htmlCopy.setValue(HtmlEntry.ANGULAR_ERRORS, AnalysisError.NO_ERRORS);
             _cache.put(templateSource, htmlCopy);
             // notify about (disappeared) HTML errors
@@ -5253,46 +5503,63 @@
         }
       }
     }
-    // invalidate new Angular errors
-    List<AngularElement> newAngularElements = library.angularElements;
-    for (AngularElement angularElement in newAngularElements) {
-      if (angularElement is AngularComponentElement) {
-        AngularComponentElement component = angularElement;
-        Source templateSource = component.templateSource;
-        if (templateSource != null) {
-          HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
-          HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
-          htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
-          _cache.put(templateSource, htmlCopy);
+    // prepare for new Angular analysis
+    if (app != null) {
+      List<AngularElement> newAngularElements = app.elements;
+      for (AngularElement angularElement in newAngularElements) {
+        if (angularElement is AngularComponentElement) {
+          AngularComponentElement component = angularElement;
+          Source templateSource = component.templateSource;
+          if (templateSource != null) {
+            HtmlEntry htmlEntry = getReadableHtmlEntry(templateSource);
+            HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+            htmlCopy.setValue(HtmlEntry.ANGULAR_APPLICATION, app);
+            htmlCopy.setValue(HtmlEntry.ANGULAR_COMPONENT, component);
+            htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
+            _cache.put(templateSource, htmlCopy);
+            _workManager.add(templateSource, SourcePriority.HTML);
+          }
         }
       }
     }
-    // remember Angular elements to resolve HTML templates later
-    dartCopy.setValue(DartEntry.ANGULAR_ELEMENTS, newAngularElements);
+    // remember Angular application
+    entry.setValue(HtmlEntry.ANGULAR_ENTRY, app);
+    entry.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
   }
 
   /**
    * Given a cache entry and a library element, record the library element and other information
    * gleaned from the element in the cache entry.
    *
+   * @param dartEntry the original cache entry from which the copy was made
    * @param dartCopy the cache entry in which data is to be recorded
    * @param library the library element used to record information
+   * @param librarySource the source for the library used to record information
    * @param htmlSource the source for the HTML library
    */
-  void recordElementData(DartEntryImpl dartCopy, LibraryElement library, Source htmlSource) {
+  void recordElementData(DartEntry dartEntry, DartEntryImpl dartCopy, LibraryElement library, Source librarySource, Source htmlSource) {
     dartCopy.setValue(DartEntry.ELEMENT, library);
     dartCopy.setValue(DartEntry.IS_LAUNCHABLE, library.entryPoint != null);
     dartCopy.setValue(DartEntry.IS_CLIENT, isClient(library, htmlSource, new Set<LibraryElement>()));
-    List<Source> unitSources = new List<Source>();
-    unitSources.add(library.definingCompilationUnit.source);
     // TODO(brianwilkerson) Understand why we're doing this both here and in
     // ResolveDartDependenciesTask and whether we should also be capturing the imported and exported
     // sources here.
-    for (CompilationUnitElement part in library.parts) {
-      Source partSource = part.source;
-      unitSources.add(partSource);
+    removeFromParts(librarySource, dartEntry);
+    List<CompilationUnitElement> parts = library.parts;
+    int count = parts.length;
+    List<Source> unitSources = new List<Source>(count + 1);
+    unitSources[0] = library.definingCompilationUnit.source;
+    for (int i = 0; i < count; i++) {
+      Source unitSource = parts[i].source;
+      unitSources[i + 1] = unitSource;
+      DartEntry unitEntry = getReadableDartEntry(unitSource);
+      if (unitSource != null) {
+        DartEntryImpl unitCopy = unitEntry.writableCopy;
+        unitCopy.addContainingLibrary(librarySource);
+        _cache.put(unitSource, unitCopy);
+      }
     }
-    dartCopy.setValue(DartEntry.INCLUDED_PARTS, new List.from(unitSources));
+    dartCopy.setValue(DartEntry.INCLUDED_PARTS, unitSources);
   }
 
   /**
@@ -5316,7 +5583,6 @@
         throw new AnalysisException.con1("Internal error: attempting to verify non-Dart file as a Dart file: ${source.fullName}");
       }
       dartEntry = sourceEntry as DartEntry;
-      _cache.accessed(source);
       int sourceTime = source.modificationStamp;
       int resultTime = task.modificationTime;
       if (sourceTime == resultTime) {
@@ -5348,8 +5614,11 @@
           // will be re-verified using the up-to-date sources.
           //
           //          dartCopy.setState(DartEntry.VERIFICATION_ERRORS, librarySource, CacheState.INVALID);
+          removeFromParts(source, dartEntry);
           dartCopy.invalidateAllInformation();
           dartCopy.modificationTime = sourceTime;
+          _cache.removedAst(source);
+          _workManager.add(source, SourcePriority.UNKNOWN);
         } else {
           //
           // We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5416,7 +5685,6 @@
         if (unitSource == librarySource) {
           libraryEntry = dartEntry;
         }
-        _cache.accessed(unitSource);
         int sourceTime = unitSource.modificationStamp;
         int resultTime = results.modificationTime;
         if (sourceTime == resultTime) {
@@ -5449,8 +5717,11 @@
               // will be re-analyzed using the up-to-date sources.
               //
               //              dartCopy.setState(DartEntry.HINTS, librarySource, CacheState.INVALID);
+              removeFromParts(unitSource, dartEntry);
               dartCopy.invalidateAllInformation();
               dartCopy.modificationTime = sourceTime;
+              _cache.removedAst(unitSource);
+              _workManager.add(unitSource, SourcePriority.UNKNOWN);
             } else {
               //
               // We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5511,7 +5782,6 @@
         throw new AnalysisException.con1("Internal error: attempting to parse non-Dart file as a Dart file: ${source.fullName}");
       }
       dartEntry = sourceEntry as DartEntry;
-      _cache.accessed(source);
       int sourceTime = source.modificationStamp;
       int resultTime = task.modificationTime;
       if (sourceTime == resultTime) {
@@ -5529,18 +5799,24 @@
           dartCopy.setValue(SourceEntry.LINE_INFO, lineInfo);
           if (task.hasPartOfDirective() && !task.hasLibraryDirective()) {
             dartCopy.setValue(DartEntry.SOURCE_KIND, SourceKind.PART);
+            _workManager.add(source, SourcePriority.NORMAL_PART);
           } else {
             dartCopy.setValue(DartEntry.SOURCE_KIND, SourceKind.LIBRARY);
+            dartCopy.containingLibrary = source;
+            _workManager.add(source, SourcePriority.LIBRARY);
           }
           dartCopy.setValue(DartEntry.PARSED_UNIT, task.compilationUnit);
           dartCopy.setValue(DartEntry.PARSE_ERRORS, task.errors);
+          _cache.storedAst(source);
           ChangeNoticeImpl notice = getNotice(source);
           notice.setErrors(dartEntry.allErrors, lineInfo);
           // Verify that the incrementally parsed and resolved unit in the incremental cache
           // is structurally equivalent to the fully parsed unit
           _incrementalAnalysisCache = IncrementalAnalysisCache.verifyStructure(_incrementalAnalysisCache, source, task.compilationUnit);
         } else {
+          removeFromParts(source, dartEntry);
           dartCopy.recordParseError();
+          _cache.removedAst(source);
         }
         dartCopy.exception = thrownException;
         _cache.put(source, dartCopy);
@@ -5554,8 +5830,11 @@
           // will be re-analyzed using the up-to-date sources.
           //
           //          dartCopy.recordParseNotInProcess();
+          removeFromParts(source, dartEntry);
           dartCopy.invalidateAllInformation();
           dartCopy.modificationTime = sourceTime;
+          _cache.removedAst(source);
+          _workManager.add(source, SourcePriority.UNKNOWN);
         } else {
           //
           // We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5595,7 +5874,6 @@
         throw new AnalysisException.con1("Internal error: attempting to parse non-HTML file as a HTML file: ${source.fullName}");
       }
       htmlEntry = sourceEntry as HtmlEntry;
-      _cache.accessed(source);
       int sourceTime = source.modificationStamp;
       int resultTime = task.modificationTime;
       if (sourceTime == resultTime) {
@@ -5615,10 +5893,12 @@
           htmlCopy.setValue(HtmlEntry.PARSED_UNIT, unit);
           htmlCopy.setValue(HtmlEntry.PARSE_ERRORS, task.errors);
           htmlCopy.setValue(HtmlEntry.REFERENCED_LIBRARIES, task.referencedLibraries);
+          _cache.storedAst(source);
           ChangeNoticeImpl notice = getNotice(source);
           notice.setErrors(htmlEntry.allErrors, lineInfo);
         } else {
           htmlCopy.recordParseError();
+          _cache.removedAst(source);
         }
         htmlCopy.exception = thrownException;
         _cache.put(source, htmlCopy);
@@ -5642,6 +5922,7 @@
           //          }
           htmlCopy.invalidateAllInformation();
           htmlCopy.modificationTime = sourceTime;
+          _cache.removedAst(source);
         } else {
           //
           // We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5650,6 +5931,7 @@
           //
           htmlCopy.setState(SourceEntry.LINE_INFO, CacheState.ERROR);
           htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.ERROR);
+          htmlCopy.setState(HtmlEntry.RESOLVED_UNIT, CacheState.ERROR);
           htmlCopy.setState(HtmlEntry.REFERENCED_LIBRARIES, CacheState.ERROR);
         }
         htmlCopy.exception = thrownException;
@@ -5682,7 +5964,6 @@
         throw new AnalysisException.con1("Internal error: attempting to resolve non-HTML file as an HTML file: ${source.fullName}");
       }
       htmlEntry = sourceEntry as HtmlEntry;
-      _cache.accessed(source);
       int sourceTime = source.modificationStamp;
       int resultTime = task.modificationTime;
       if (sourceTime == resultTime) {
@@ -5724,6 +6005,87 @@
           //          }
           htmlCopy.invalidateAllInformation();
           htmlCopy.modificationTime = sourceTime;
+          _cache.removedAst(source);
+        } else {
+          //
+          // We could not determine whether the sources were up-to-date or out-of-date. Mark the
+          // cache so that we won't attempt to re-analyze the sources until there's a good chance
+          // that we'll be able to do so without error.
+          //
+          htmlCopy.recordResolutionError();
+        }
+        htmlCopy.exception = thrownException;
+        _cache.put(source, htmlCopy);
+        htmlEntry = htmlCopy;
+      }
+    }
+    if (thrownException != null) {
+      throw thrownException;
+    }
+    return htmlEntry;
+  }
+
+  /**
+   * Record the results produced by performing a [ResolveAngularEntryHtmlTask]. If the results
+   * were computed from data that is now out-of-date, then the results will not be recorded.
+   *
+   * @param task the task that was performed
+   * @throws AnalysisException if the results could not be recorded
+   */
+  HtmlEntry recordResolveAngularEntryHtmlTaskResults(ResolveAngularEntryHtmlTask task) {
+    Source source = task.source;
+    AnalysisException thrownException = task.exception;
+    HtmlEntry htmlEntry = null;
+    {
+      SourceEntry sourceEntry = _cache.get(source);
+      if (sourceEntry is! HtmlEntry) {
+        // This shouldn't be possible because we should never have performed the task if the source
+        // didn't represent an HTML file, but check to be safe.
+        throw new AnalysisException.con1("Internal error: attempting to resolve non-HTML file as an HTML file: ${source.fullName}");
+      }
+      htmlEntry = sourceEntry as HtmlEntry;
+      int sourceTime = source.modificationStamp;
+      int resultTime = task.modificationTime;
+      if (sourceTime == resultTime) {
+        if (htmlEntry.modificationTime != sourceTime) {
+          // The source has changed without the context being notified. Simulate notification.
+          sourceChanged(source);
+          htmlEntry = getReadableHtmlEntry(source);
+          if (htmlEntry == null) {
+            throw new AnalysisException.con1("An HTML file became a non-HTML file: ${source.fullName}");
+          }
+        }
+        HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+        if (thrownException == null) {
+          htmlCopy.setValue(HtmlEntry.ANGULAR_ERRORS, task.resolutionErrors);
+          ChangeNoticeImpl notice = getNotice(source);
+          notice.htmlUnit = task.resolvedUnit;
+          notice.setErrors(htmlCopy.allErrors, htmlCopy.getValue(SourceEntry.LINE_INFO));
+        } else {
+          htmlCopy.recordResolutionError();
+        }
+        htmlCopy.exception = thrownException;
+        _cache.put(source, htmlCopy);
+        htmlEntry = htmlCopy;
+      } else {
+        HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
+        if (thrownException == null || resultTime >= 0) {
+          //
+          // The analysis was performed on out-of-date sources. Mark the cache so that the sources
+          // will be re-analyzed using the up-to-date sources.
+          //
+          //          if (htmlCopy.getState(HtmlEntry.ANGULAR_ERRORS) == CacheState.IN_PROCESS) {
+          //            htmlCopy.setState(HtmlEntry.ANGULAR_ERRORS, CacheState.INVALID);
+          //          }
+          //          if (htmlCopy.getState(HtmlEntry.ELEMENT) == CacheState.IN_PROCESS) {
+          //            htmlCopy.setState(HtmlEntry.ELEMENT, CacheState.INVALID);
+          //          }
+          //          if (htmlCopy.getState(HtmlEntry.RESOLUTION_ERRORS) == CacheState.IN_PROCESS) {
+          //            htmlCopy.setState(HtmlEntry.RESOLUTION_ERRORS, CacheState.INVALID);
+          //          }
+          htmlCopy.invalidateAllInformation();
+          htmlCopy.modificationTime = sourceTime;
+          _cache.removedAst(source);
         } else {
           //
           // We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5763,7 +6125,6 @@
         throw new AnalysisException.con1("Internal error: attempting to resolve Dart dependencies in a non-Dart file: ${source.fullName}");
       }
       dartEntry = sourceEntry as DartEntry;
-      _cache.accessed(source);
       int sourceTime = source.modificationStamp;
       int resultTime = task.modificationTime;
       if (sourceTime == resultTime) {
@@ -5775,11 +6136,22 @@
             throw new AnalysisException.con1("A Dart file became a non-Dart file: ${source.fullName}");
           }
         }
+        removeFromParts(source, dartEntry);
         DartEntryImpl dartCopy = dartEntry.writableCopy;
         if (thrownException == null) {
+          List<Source> newParts = task.includedSources;
+          for (int i = 0; i < newParts.length; i++) {
+            Source partSource = newParts[i];
+            DartEntry partEntry = getReadableDartEntry(partSource);
+            if (partEntry != null && partEntry != dartEntry) {
+              DartEntryImpl partCopy = partEntry.writableCopy;
+              partCopy.addContainingLibrary(source);
+              _cache.put(partSource, partCopy);
+            }
+          }
           dartCopy.setValue(DartEntry.EXPORTED_LIBRARIES, task.exportedSources);
           dartCopy.setValue(DartEntry.IMPORTED_LIBRARIES, task.importedSources);
-          dartCopy.setValue(DartEntry.INCLUDED_PARTS, task.includedSources);
+          dartCopy.setValue(DartEntry.INCLUDED_PARTS, newParts);
         } else {
           dartCopy.recordDependencyError();
         }
@@ -5795,8 +6167,11 @@
           // will be re-analyzed using the up-to-date sources.
           //
           //          dartCopy.recordDependencyNotInProcess();
+          removeFromParts(source, dartEntry);
           dartCopy.invalidateAllInformation();
           dartCopy.modificationTime = sourceTime;
+          _cache.removedAst(source);
+          _workManager.add(source, SourcePriority.UNKNOWN);
         } else {
           //
           // We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5839,7 +6214,6 @@
         throw new AnalysisException.con1("Internal error: attempting to resolve non-Dart file as a Dart file: ${unitSource.fullName}");
       }
       dartEntry = sourceEntry as DartEntry;
-      _cache.accessed(unitSource);
       int sourceTime = unitSource.modificationStamp;
       int resultTime = task.modificationTime;
       if (sourceTime == resultTime) {
@@ -5854,8 +6228,10 @@
         DartEntryImpl dartCopy = dartEntry.writableCopy;
         if (thrownException == null) {
           dartCopy.setValue2(DartEntry.RESOLVED_UNIT, librarySource, task.resolvedUnit);
+          _cache.storedAst(unitSource);
         } else {
           dartCopy.setState2(DartEntry.RESOLVED_UNIT, librarySource, CacheState.ERROR);
+          _cache.removedAst(unitSource);
         }
         dartCopy.exception = thrownException;
         _cache.put(unitSource, dartCopy);
@@ -5871,8 +6247,11 @@
           //          if (dartCopy.getState(DartEntry.RESOLVED_UNIT) == CacheState.IN_PROCESS) {
           //            dartCopy.setState(DartEntry.RESOLVED_UNIT, librarySource, CacheState.INVALID);
           //          }
+          removeFromParts(unitSource, dartEntry);
           dartCopy.invalidateAllInformation();
           dartCopy.modificationTime = sourceTime;
+          _cache.removedAst(unitSource);
+          _workManager.add(unitSource, SourcePriority.UNKNOWN);
         } else {
           //
           // We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5912,7 +6291,6 @@
         throw new AnalysisException.con1("Internal error: attempting to resolve non-HTML file as an HTML file: ${source.fullName}");
       }
       htmlEntry = sourceEntry as HtmlEntry;
-      _cache.accessed(source);
       int sourceTime = source.modificationStamp;
       int resultTime = task.modificationTime;
       if (sourceTime == resultTime) {
@@ -5926,15 +6304,20 @@
         }
         HtmlEntryImpl htmlCopy = htmlEntry.writableCopy;
         if (thrownException == null) {
+          htmlCopy.setState(HtmlEntry.PARSED_UNIT, CacheState.FLUSHED);
+          htmlCopy.setValue(HtmlEntry.RESOLVED_UNIT, task.resolvedUnit);
           htmlCopy.setValue(HtmlEntry.ELEMENT, task.element);
           htmlCopy.setValue(HtmlEntry.RESOLUTION_ERRORS, task.resolutionErrors);
+          _cache.storedAst(source);
           ChangeNoticeImpl notice = getNotice(source);
           notice.htmlUnit = task.resolvedUnit;
           notice.setErrors(htmlCopy.allErrors, htmlCopy.getValue(SourceEntry.LINE_INFO));
         } else {
           htmlCopy.recordResolutionError();
+          _cache.removedAst(source);
         }
         htmlCopy.exception = thrownException;
+        recordAngularComponents(htmlCopy, task.angularApplication);
         _cache.put(source, htmlCopy);
         htmlEntry = htmlCopy;
       } else {
@@ -5953,6 +6336,7 @@
           //          }
           htmlCopy.invalidateAllInformation();
           htmlCopy.modificationTime = sourceTime;
+          _cache.removedAst(source);
         } else {
           //
           // We could not determine whether the sources were up-to-date or out-of-date. Mark the
@@ -5973,6 +6357,46 @@
   }
 
   /**
+   * Remove the given library from the list of containing libraries for all of the parts referenced
+   * by the given entry.
+   *
+   * <b>Note:</b> This method must only be invoked while we are synchronized on [cacheLock].
+   *
+   * @param librarySource the library to be removed
+   * @param dartEntry the entry containing the list of included parts
+   */
+  void removeFromParts(Source librarySource, DartEntry dartEntry) {
+    List<Source> oldParts = dartEntry.getValue(DartEntry.INCLUDED_PARTS);
+    for (int i = 0; i < oldParts.length; i++) {
+      Source partSource = oldParts[i];
+      DartEntry partEntry = getReadableDartEntry(partSource);
+      if (partEntry != null && partEntry != dartEntry) {
+        DartEntryImpl partCopy = partEntry.writableCopy;
+        partCopy.removeContainingLibrary(librarySource);
+        _cache.put(partSource, partCopy);
+      }
+    }
+  }
+
+  /**
+   * Remove the given source from the priority order if it is in the list.
+   *
+   * @param source the source to be removed
+   */
+  void removeFromPriorityOrder(Source source) {
+    int count = _priorityOrder.length;
+    List<Source> newOrder = new List<Source>();
+    for (int i = 0; i < count; i++) {
+      if (_priorityOrder[i] != source) {
+        newOrder.add(_priorityOrder[i]);
+      }
+    }
+    if (newOrder.length < count) {
+      analysisPriorityOrder = newOrder;
+    }
+  }
+
+  /**
    * Create an entry for the newly added source. Return `true` if the new source is a Dart
    * file.
    *
@@ -5994,6 +6418,11 @@
       _cache.put(source, sourceCopy);
       logInformation("Added new source: ${debuggingString(source)} (previously modified at ${oldTime})");
     }
+    if (sourceEntry is HtmlEntry) {
+      _workManager.add(source, SourcePriority.HTML);
+    } else {
+      _workManager.add(source, SourcePriority.UNKNOWN);
+    }
     return sourceEntry is DartEntry;
   }
 
@@ -6020,6 +6449,8 @@
       htmlCopy.modificationTime = source.modificationStamp;
       htmlCopy.invalidateAllInformation();
       _cache.put(source, htmlCopy);
+      _cache.removedAst(source);
+      _workManager.add(source, SourcePriority.HTML);
       logInformation("Modified HTML source: ${debuggingString(source)} (previously modified at ${oldTime})");
     } else if (sourceEntry is DartEntry) {
       List<Source> containingLibraries = getLibrariesContaining(source);
@@ -6037,10 +6468,13 @@
         //    for (Source library : containingLibraries) {
         invalidateLibraryResolution(library, writer);
       }
+      removeFromParts(source, sourceEntry);
       DartEntryImpl dartCopy = sourceEntry.writableCopy;
       dartCopy.modificationTime = source.modificationStamp;
       dartCopy.invalidateAllInformation();
       _cache.put(source, dartCopy);
+      _cache.removedAst(source);
+      _workManager.add(source, SourcePriority.UNKNOWN);
       logInformation(writer.toString());
     }
   }
@@ -6067,6 +6501,8 @@
       }
     }
     _cache.remove(source);
+    _workManager.remove(source);
+    removeFromPriorityOrder(source);
     logInformation(writer.toString());
   }
 
@@ -6081,6 +6517,7 @@
    */
   bool validateCacheConsistency() {
     int consistencyCheckStart = JavaSystem.nanoTime();
+    List<Source> missingSources = new List<Source>();
     int inconsistentCount = 0;
     {
       for (MapEntry<Source, SourceEntry> entry in _cache.entrySet()) {
@@ -6091,10 +6528,29 @@
           sourceChanged(source);
           inconsistentCount++;
         }
+        if (sourceEntry.exception != null) {
+          if (!source.exists()) {
+            missingSources.add(source);
+          }
+        }
       }
     }
     int consistencyCheckEnd = JavaSystem.nanoTime();
-    logInformation("Consistency check found ${inconsistentCount} inconsistent entries in ${((consistencyCheckEnd - consistencyCheckStart) / 1000000.0)} ms");
+    PrintStringWriter writer = new PrintStringWriter();
+    writer.print("Consistency check took ");
+    writer.print((consistencyCheckEnd - consistencyCheckStart) / 1000000.0);
+    writer.println(" ms and found");
+    writer.print("  ");
+    writer.print(inconsistentCount);
+    writer.println(" inconsistent entries");
+    writer.print("  ");
+    writer.print(missingSources.length);
+    writer.println(" missing sources");
+    for (Source source in missingSources) {
+      writer.print("    ");
+      writer.println(source.fullName);
+    }
+    logInformation(writer.toString());
     return inconsistentCount > 0;
   }
 }
@@ -6120,6 +6576,8 @@
 
   HtmlEntry visitResolveAngularComponentTemplateTask(ResolveAngularComponentTemplateTask task) => AnalysisContextImpl_this.recordResolveAngularComponentTemplateTaskResults(task);
 
+  SourceEntry visitResolveAngularEntryHtmlTask(ResolveAngularEntryHtmlTask task) => AnalysisContextImpl_this.recordResolveAngularEntryHtmlTaskResults(task);
+
   DartEntry visitResolveDartDependenciesTask(ResolveDartDependenciesTask task) => AnalysisContextImpl_this.recordResolveDartDependenciesTaskResults(task);
 
   DartEntry visitResolveDartLibraryTask(ResolveDartLibraryTask task) => AnalysisContextImpl_this.recordResolveDartLibraryTaskResults(task);
@@ -6917,6 +7375,8 @@
     }
   }
 
+  ResolvableHtmlUnit computeResolvableAngularComponentHtmlUnit(Source source) => _basis.computeResolvableAngularComponentHtmlUnit(source);
+
   ResolvableCompilationUnit computeResolvableCompilationUnit(Source source) => _basis.computeResolvableCompilationUnit(source);
 
   ResolvableHtmlUnit computeResolvableHtmlUnit(Source source) => _basis.computeResolvableHtmlUnit(source);
@@ -7078,16 +7538,6 @@
     }
   }
 
-  List<AngularElement> getLibraryAngularElements(Source source) {
-    InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-getLibraryAngularElements");
-    try {
-      instrumentation.metric3("contextId", _contextId);
-      return _basis.getLibraryAngularElements(source);
-    } finally {
-      instrumentation.log();
-    }
-  }
-
   LibraryElement getLibraryElement(Source source) {
     InstrumentationBuilder instrumentation = Instrumentation.builder2("Analysis-getLibraryElement");
     try {
@@ -7388,6 +7838,16 @@
 
   /**
    * Return an AST structure corresponding to the given source, but ensure that the structure has
+   * not already been resolved and will not be resolved by any other threads.
+   *
+   * @param source the compilation unit for which an AST structure should be returned
+   * @return the AST structure representing the content of the source
+   * @throws AnalysisException if the analysis could not be performed
+   */
+  ResolvableHtmlUnit computeResolvableAngularComponentHtmlUnit(Source source);
+
+  /**
+   * Return an AST structure corresponding to the given source, but ensure that the structure has
    * not already been resolved and will not be resolved by any other threads or in any other
    * library.
    *
@@ -7717,6 +8177,44 @@
 }
 
 /**
+ * The enumerated type `Priority` defines the priority levels used to return sources in an
+ * optimal order.
+ */
+class SourcePriority extends Enum<SourcePriority> {
+  /**
+   * Used for a Dart source that is known to be a part contained in a library that was recently
+   * resolved. These parts are given a higher priority because there is a high probability that
+   * their AST structure is still in the cache and therefore would not need to be re-created.
+   */
+  static final SourcePriority PRIORITY_PART = new SourcePriority('PRIORITY_PART', 0);
+
+  /**
+   * Used for a Dart source that is known to be a library.
+   */
+  static final SourcePriority LIBRARY = new SourcePriority('LIBRARY', 1);
+
+  /**
+   * Used for a Dart source that is known to be a part but whose library has not yet been
+   * resolved.
+   */
+  static final SourcePriority NORMAL_PART = new SourcePriority('NORMAL_PART', 2);
+
+  /**
+   * Used for a Dart source whose kind is unknown.
+   */
+  static final SourcePriority UNKNOWN = new SourcePriority('UNKNOWN', 3);
+
+  /**
+   * Used for an HTML source.
+   */
+  static final SourcePriority HTML = new SourcePriority('HTML', 4);
+
+  static final List<SourcePriority> values = [PRIORITY_PART, LIBRARY, NORMAL_PART, UNKNOWN, HTML];
+
+  SourcePriority(String name, int ordinal) : super(name, ordinal);
+}
+
+/**
  * Instances of the class `TimestampedData` represent analysis data for which we have a
  * modification time.
  */
@@ -7741,21 +8239,194 @@
 }
 
 /**
+ * Instances of the class `WorkManager` manage a list of sources that need to have analysis
+ * work performed on them.
+ */
+class WorkManager {
+  /**
+   * An array containing the various queues is priority order.
+   */
+  List<List<Source>> _workQueues;
+
+  /**
+   * Initialize a newly created manager to have no work queued up.
+   */
+  WorkManager() {
+    int queueCount = SourcePriority.values.length;
+    _workQueues = new List<List>(queueCount);
+    for (int i = 0; i < queueCount; i++) {
+      _workQueues[i] = new List<Source>();
+    }
+  }
+
+  /**
+   * Record that the given source needs to be analyzed. The priority level is used to control when
+   * the source will be analyzed with respect to other sources.
+   *
+   * @param source the source that needs to be analyzed
+   * @param priority the priority level of the source
+   */
+  void add(Source source, SourcePriority priority) {
+    // TODO(brianwilkerson) Optimize the order of the libraries so that libraries that depend on
+    // other libraries get analyzed after the other libraries.
+    int queueCount = _workQueues.length;
+    int ordinal = priority.ordinal;
+    for (int i = 0; i < queueCount; i++) {
+      List<Source> queue = _workQueues[i];
+      if (i == ordinal) {
+        if (!queue.contains(source)) {
+          queue.add(source);
+        }
+      } else {
+        queue.remove(source);
+      }
+    }
+  }
+
+  /**
+   * Return the next source for which some analysis work needs to be done.
+   *
+   * @return the next source for which some analysis work needs to be done
+   */
+  Source get nextSource {
+    int queueCount = _workQueues.length;
+    for (int i = 0; i < queueCount; i++) {
+      List<Source> queue = _workQueues[i];
+      if (!queue.isEmpty) {
+        return queue[0];
+      }
+    }
+    return null;
+  }
+
+  /**
+   * Record that the given source is fully analyzed.
+   *
+   * @param source the source that is fully analyzed
+   */
+  void remove(Source source) {
+    int queueCount = _workQueues.length;
+    for (int i = 0; i < queueCount; i++) {
+      _workQueues[i].remove(source);
+    }
+  }
+}
+
+/**
+ * An [Expression] with optional [AngularFilterNode]s.
+ *
+ * @coverage dart.engine.ast
+ */
+class AngularExpression {
+  /**
+   * The [Expression] to apply filters to.
+   */
+  final Expression expression;
+
+  /**
+   * The filters to apply.
+   */
+  final List<AngularFilterNode> filters;
+
+  AngularExpression(this.expression, this.filters);
+
+  /**
+   * Return the offset of the character immediately following the last character of this node's
+   * source range. This is equivalent to `node.getOffset() + node.getLength()`.
+   *
+   * @return the offset of the character just past the node's source range
+   */
+  int get end {
+    if (filters.isEmpty) {
+      return expression.end;
+    }
+    AngularFilterNode lastFilter = filters[filters.length - 1];
+    List<AngularFilterArgument> filterArguments = lastFilter.arguments;
+    if (filterArguments.isEmpty) {
+      return lastFilter.name.end;
+    }
+    return filterArguments[filterArguments.length - 1].expression.end;
+  }
+
+  /**
+   * Return Dart [Expression]s this Angular expression consists of.
+   */
+  List<Expression> get expressions {
+    List<Expression> expressions = [];
+    expressions.add(expression);
+    for (AngularFilterNode filter in filters) {
+      expressions.add(filter.name);
+      for (AngularFilterArgument filterArgument in filter.arguments) {
+        expressions.addAll(filterArgument.subExpressions);
+        expressions.add(filterArgument.expression);
+      }
+    }
+    return expressions;
+  }
+
+  /**
+   * Return the number of characters in the expression's source range.
+   */
+  int get length => end - offset;
+
+  /**
+   * Return the offset of the first character in the expression's source range.
+   */
+  int get offset => expression.offset;
+}
+
+/**
+ * Angular filter argument.
+ *
+ * @coverage dart.engine.ast
+ */
+class AngularFilterArgument {
+  /**
+   * The [TokenType#COLON] token.
+   */
+  final Token token;
+
+  /**
+   * The argument expression.
+   */
+  final Expression expression;
+
+  /**
+   * The optional sub-[Expression]s.
+   */
+  List<Expression> subExpressions = Expression.EMPTY_ARRAY;
+
+  AngularFilterArgument(this.token, this.expression);
+}
+
+/**
+ * Angular filter node.
+ *
+ * @coverage dart.engine.ast
+ */
+class AngularFilterNode {
+  /**
+   * The [TokenType#BAR] token.
+   */
+  final Token token;
+
+  /**
+   * The name of the filter.
+   */
+  final SimpleIdentifier name;
+
+  /**
+   * The arguments for this filter.
+   */
+  final List<AngularFilterArgument> arguments;
+
+  AngularFilterNode(this.token, this.name, this.arguments);
+}
+
+/**
  * Instances of the class [AngularHtmlUnitResolver] resolve Angular specific expressions.
  */
 class AngularHtmlUnitResolver extends ht.RecursiveXmlVisitor<Object> {
-  static int _OPENING_DELIMITER_CHAR = 0x7B;
-
-  static int _CLOSING_DELIMITER_CHAR = 0x7D;
-
-  static String _OPENING_DELIMITER = "{{";
-
-  static String _CLOSING_DELIMITER = "}}";
-
-  static int _OPENING_DELIMITER_LENGTH = _OPENING_DELIMITER.length;
-
-  static int _CLOSING_DELIMITER_LENGTH = _CLOSING_DELIMITER.length;
-
   static String _NG_APP = "ng-app";
 
   /**
@@ -7776,6 +8447,21 @@
   }
 
   /**
+   * Returns the array of all top-level Angular elements that could be used in the application with
+   * this entry point. Maybe `null` of not an Angular entry point.
+   */
+  static List<AngularElement> getAngularElements(AnalysisContext context, ht.HtmlUnit unit) {
+    if (hasAngularAnnotation(unit)) {
+      CompilationUnit dartUnit = getDartUnit(context, unit);
+      if (dartUnit != null) {
+        LibraryElement libraryElement = dartUnit.element.library;
+        return getAngularElements2(libraryElement);
+      }
+    }
+    return null;
+  }
+
+  /**
    * @return `true` if the given [HtmlUnit] has <code>ng-app</code> annotation.
    */
   static bool hasAngularAnnotation(ht.HtmlUnit htmlUnit) {
@@ -7792,8 +8478,72 @@
     return new SimpleIdentifier(token);
   }
 
+  /**
+   * Adds [AngularElement] declared by the given top-level [Element].
+   *
+   * @param angularElements the list to fill with top-level [AngularElement]s
+   * @param classElement the [ClassElement] to get [AngularElement]s from
+   */
+  static void addAngularElements(Set<AngularElement> angularElements, ClassElement classElement) {
+    for (ToolkitObjectElement toolkitObject in classElement.toolkitObjects) {
+      if (toolkitObject is AngularElement) {
+        angularElements.add(toolkitObject);
+      }
+    }
+  }
+
+  /**
+   * Returns the array of all top-level Angular elements that could be used in this library.
+   *
+   * @param libraryElement the [LibraryElement] to analyze
+   * @return the array of all top-level Angular elements that could be used in this library
+   */
+  static void addAngularElements2(Set<AngularElement> angularElements, LibraryElement library, Set<LibraryElement> visited) {
+    if (!visited.add(library)) {
+      return;
+    }
+    // add Angular elements from current library
+    for (CompilationUnitElement unit in library.units) {
+      for (ClassElement type in unit.types) {
+        addAngularElements(angularElements, type);
+      }
+    }
+    // handle imports
+    for (ImportElement importElement in library.imports) {
+      LibraryElement importedLibrary = importElement.importedLibrary;
+      addAngularElements2(angularElements, importedLibrary, visited);
+    }
+  }
+
   static StringToken createStringToken(String name, int offset) => new StringToken(TokenType.IDENTIFIER, name, offset);
 
+  /**
+   * Returns the array of all top-level Angular elements that could be used in this library.
+   *
+   * @param libraryElement the [LibraryElement] to analyze
+   * @return the array of all top-level Angular elements that could be used in this library
+   */
+  static List<AngularElement> getAngularElements2(LibraryElement libraryElement) {
+    Set<AngularElement> angularElements = new Set();
+    addAngularElements2(angularElements, libraryElement, new Set());
+    return new List.from(angularElements);
+  }
+
+  /**
+   * Returns the external Dart [CompilationUnit] referenced by the given [HtmlUnit].
+   */
+  static CompilationUnit getDartUnit(AnalysisContext context, ht.HtmlUnit unit) {
+    for (HtmlScriptElement script in unit.element.scripts) {
+      if (script is ExternalHtmlScriptElement) {
+        Source scriptSource = script.scriptSource;
+        if (scriptSource != null) {
+          return context.resolveCompilationUnit2(scriptSource, scriptSource);
+        }
+      }
+    }
+    return null;
+  }
+
   InternalAnalysisContext _context;
 
   TypeProvider _typeProvider;
@@ -7838,40 +8588,69 @@
   }
 
   /**
-   * Resolves [source] as an [AngularComponentElement] template file.
-   *
-   * @param angularElements the [AngularElement]s accessible in the component's library, not
-   *          `null`
-   * @param component the [AngularComponentElement] to resolve template for, not `null`
+   * The [AngularApplicationInfo] for the Web application with this entry point, may be
+   * `null` if not an entry point.
    */
-  void resolveComponentTemplate(List<AngularElement> angularElements, AngularComponentElement component) {
-    _isAngular = true;
-    resolveInternal(angularElements, component);
+  AngularApplicationInfo calculateAngularApplication() {
+    // check if Angular at all
+    if (!hasAngularAnnotation(_unit)) {
+      return null;
+    }
+    // prepare resolved Dart unit
+    CompilationUnit dartUnit = getDartUnit(_context, _unit);
+    if (dartUnit == null) {
+      return null;
+    }
+    // prepare accessible Angular elements
+    LibraryElement libraryElement = dartUnit.element.library;
+    List<AngularElement> angularElements = getAngularElements2(libraryElement);
+    // resolve template URIs
+    // TODO(scheglov) resolve to HtmlElement to allow F3 ?
+    for (AngularElement angularElement in angularElements) {
+      if (angularElement is AngularComponentElement) {
+        AngularComponentElement component = angularElement;
+        String templateUri = component.templateUri;
+        if (templateUri == null) {
+          continue;
+        }
+        try {
+          Source templateSource = _source.resolveRelative(parseUriWithException(templateUri));
+          if (templateSource == null || !templateSource.exists()) {
+            templateSource = _context.sourceFactory.resolveUri(_source, "package:${templateUri}");
+            if (templateSource == null || !templateSource.exists()) {
+              reportError7(component.templateUriOffset, templateUri.length, AngularCode.URI_DOES_NOT_EXIST, [templateUri]);
+              continue;
+            }
+          }
+          if (!AnalysisEngine.isHtmlFileName(templateUri)) {
+            continue;
+          }
+          (component as AngularComponentElementImpl).templateSource = templateSource;
+        } on URISyntaxException catch (exception) {
+          reportError7(component.templateUriOffset, templateUri.length, AngularCode.INVALID_URI, [templateUri]);
+        }
+      }
+    }
+    // done
+    return new AngularApplicationInfo(_source, angularElements);
   }
 
   /**
-   * Resolves [source] as an entry-point HTML file, that references an external Dart script.
+   * Resolves [source] as an [AngularComponentElement] template file.
+   *
+   * @param application the Angular application we are resolving for
+   * @param component the [AngularComponentElement] to resolve template for, not `null`
    */
-  void resolveEntryPoint() {
-    // check if Angular at all
-    if (!hasAngularAnnotation(_unit)) {
-      return;
-    }
-    // prepare accessible Angular elements
-    List<AngularElement> angularElements;
-    {
-      // prepare external Dart script source
-      Source dartSource = getDartSource(_unit);
-      if (dartSource == null) {
-        return;
-      }
-      // ensure resolved
-      _context.resolveCompilationUnit2(dartSource, dartSource);
-      // get cached Angular elements
-      angularElements = _context.getLibraryAngularElements(dartSource);
-    }
-    // perform resolution
-    resolveInternal(angularElements, null);
+  void resolveComponentTemplate(AngularApplicationInfo application, AngularComponentElement component) {
+    _isAngular = true;
+    resolveInternal(application.elements, component);
+  }
+
+  /**
+   * Resolves [source] as an Angular application entry point.
+   */
+  void resolveEntryPoint(AngularApplicationInfo application) {
+    resolveInternal(application.elements, null);
   }
 
   Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
@@ -7976,16 +8755,63 @@
   TypeProvider get typeProvider => _typeProvider;
 
   /**
-   * Parses given [String] as an [Expression] at the given offset.
+   * Parses given [String] as an [AngularExpression] at the given offset.
    */
-  Expression parseExpression(String contents, int offset) => parseExpression2(contents, 0, contents.length, offset);
+  AngularExpression parseAngularExpression(String contents, int offset) => parseAngularExpression2(contents, 0, contents.length, offset);
 
-  Expression parseExpression2(String contents, int startIndex, int endIndex, int offset) {
+  AngularExpression parseAngularExpression2(String contents, int startIndex, int endIndex, int offset) {
     Token token = scanDart(contents, startIndex, endIndex, offset);
-    return parseExpression3(token);
+    return parseAngularExpression3(token);
   }
 
-  Expression parseExpression3(Token token) => ht.HtmlParser.parseEmbeddedExpression(_source, token, _errorListener);
+  AngularExpression parseAngularExpression3(Token token) {
+    List<Token> tokens = splitAtBar(token);
+    Expression mainExpression = parseDartExpression3(tokens[0]);
+    // parse filters
+    List<AngularFilterNode> filters = [];
+    for (int i = 1; i < tokens.length; i++) {
+      Token filterToken = tokens[i];
+      Token barToken = filterToken;
+      filterToken = filterToken.next;
+      // TODO(scheglov) report missing identifier
+      SimpleIdentifier name = parseDartExpression3(filterToken) as SimpleIdentifier;
+      filterToken = name.endToken.next;
+      // parse arguments
+      List<AngularFilterArgument> arguments = [];
+      while (filterToken.type != TokenType.EOF) {
+        // skip ":"
+        Token colonToken = filterToken;
+        if (identical(colonToken.type, TokenType.COLON)) {
+          filterToken = filterToken.next;
+        } else {
+          reportError8(colonToken, AngularCode.MISSING_FILTER_COLON, []);
+        }
+        // parse argument
+        Expression argument = parseDartExpression3(filterToken);
+        arguments.add(new AngularFilterArgument(colonToken, argument));
+        // next token
+        filterToken = argument.endToken.next;
+      }
+      filters.add(new AngularFilterNode(barToken, name, arguments));
+    }
+    // done
+    return new AngularExpression(mainExpression, filters);
+  }
+
+  /**
+   * Parses given [String] as an [Expression] at the given offset.
+   */
+  Expression parseDartExpression(String contents, int offset) => parseDartExpression2(contents, 0, contents.length, offset);
+
+  Expression parseDartExpression2(String contents, int startIndex, int endIndex, int offset) {
+    Token token = scanDart(contents, startIndex, endIndex, offset);
+    return parseDartExpression3(token);
+  }
+
+  Expression parseDartExpression3(Token token) {
+    Parser parser = new Parser(_source, _errorListener);
+    return parser.parseExpression(token);
+  }
 
   void popNameScope() {
     _nameScope = _resolver.popNameScope();
@@ -8010,6 +8836,20 @@
   }
 
   /**
+   * Reports given [ErrorCode] at the given [Token].
+   */
+  void reportError8(Token token, ErrorCode errorCode, List<Object> arguments) {
+    reportError7(token.offset, token.length, errorCode, arguments);
+  }
+
+  void resolveExpression(AngularExpression angularExpression) {
+    List<Expression> dartExpressions = angularExpression.expressions;
+    for (Expression dartExpression in dartExpressions) {
+      resolveNode(dartExpression);
+    }
+  }
+
+  /**
    * Resolves given [ASTNode] using [resolver].
    */
   void resolveNode(ASTNode node) {
@@ -8030,6 +8870,8 @@
     // create LibraryElementImpl
     _libraryElement = new LibraryElementImpl(_context, null);
     _libraryElement.definingCompilationUnit = _unitElement;
+    _libraryElement.angularHtml = true;
+    _injectedLibraries.add(_libraryElement);
     // create FunctionElementImpl
     _functionElement = new FunctionElementImpl.con2(0);
     _unitElement.functions = <FunctionElement> [_functionElement];
@@ -8073,18 +8915,14 @@
   }
 
   /**
-   * Returns the external Dart script [Source] referenced by the given [HtmlUnit].
+   * Defines variable for the given [AngularElement].
    */
-  Source getDartSource(ht.HtmlUnit unit) {
-    for (HtmlScriptElement script in unit.element.scripts) {
-      if (script is ExternalHtmlScriptElement) {
-        Source scriptSource = script.scriptSource;
-        if (scriptSource != null) {
-          return scriptSource;
-        }
-      }
-    }
-    return null;
+  void defineTopElementVariable(AngularElement element) {
+    ClassElement classElement = element.enclosingElement as ClassElement;
+    InterfaceType type = classElement.type;
+    LocalVariableElementImpl variable = createLocalVariable2(type, element.name);
+    defineTopVariable(variable);
+    variable.toolkitObjects = <AngularElement> [element];
   }
 
   /**
@@ -8094,28 +8932,28 @@
    * @param expressions the list to which embedded expressions are to be added
    * @param token the token whose value is to be parsed
    */
-  void parseEmbeddedExpressions(List<ht.EmbeddedExpression> expressions, ht.Token token) {
+  void parseEmbeddedExpressions(List<AngularMoustacheXmlExpression> expressions, ht.Token token) {
     // prepare Token information
     String lexeme = token.lexeme;
     int offset = token.offset;
     // find expressions between {{ and }}
-    int startIndex = StringUtilities.indexOf2(lexeme, 0, _OPENING_DELIMITER_CHAR, _OPENING_DELIMITER_CHAR);
+    int startIndex = StringUtilities.indexOf2(lexeme, 0, AngularMoustacheXmlExpression.OPENING_DELIMITER_CHAR, AngularMoustacheXmlExpression.OPENING_DELIMITER_CHAR);
     while (startIndex >= 0) {
-      int endIndex = StringUtilities.indexOf2(lexeme, startIndex + _OPENING_DELIMITER_LENGTH, _CLOSING_DELIMITER_CHAR, _CLOSING_DELIMITER_CHAR);
+      int endIndex = StringUtilities.indexOf2(lexeme, startIndex + AngularMoustacheXmlExpression.OPENING_DELIMITER_LENGTH, AngularMoustacheXmlExpression.CLOSING_DELIMITER_CHAR, AngularMoustacheXmlExpression.CLOSING_DELIMITER_CHAR);
       if (endIndex < 0) {
         // TODO(brianwilkerson) Should we report this error or will it be reported by something else?
         return;
-      } else if (startIndex + _OPENING_DELIMITER_LENGTH < endIndex) {
-        startIndex += _OPENING_DELIMITER_LENGTH;
-        Expression expression = parseExpression2(lexeme, startIndex, endIndex, offset);
-        expressions.add(new ht.EmbeddedExpression(startIndex, expression, endIndex));
+      } else if (startIndex + AngularMoustacheXmlExpression.OPENING_DELIMITER_LENGTH < endIndex) {
+        startIndex += AngularMoustacheXmlExpression.OPENING_DELIMITER_LENGTH;
+        AngularExpression expression = parseAngularExpression2(lexeme, startIndex, endIndex, offset);
+        expressions.add(new AngularMoustacheXmlExpression(startIndex, endIndex, expression));
       }
-      startIndex = StringUtilities.indexOf2(lexeme, endIndex + _CLOSING_DELIMITER_LENGTH, _OPENING_DELIMITER_CHAR, _OPENING_DELIMITER_CHAR);
+      startIndex = StringUtilities.indexOf2(lexeme, endIndex + AngularMoustacheXmlExpression.CLOSING_DELIMITER_LENGTH, AngularMoustacheXmlExpression.OPENING_DELIMITER_CHAR, AngularMoustacheXmlExpression.OPENING_DELIMITER_CHAR);
     }
   }
 
   void parseEmbeddedExpressions2(ht.XmlAttributeNode node) {
-    List<ht.EmbeddedExpression> expressions = new List<ht.EmbeddedExpression>();
+    List<AngularMoustacheXmlExpression> expressions = [];
     parseEmbeddedExpressions(expressions, node.valueToken);
     if (!expressions.isEmpty) {
       node.expressions = new List.from(expressions);
@@ -8123,7 +8961,7 @@
   }
 
   void parseEmbeddedExpressions3(ht.XmlTagNode node) {
-    List<ht.EmbeddedExpression> expressions = new List<ht.EmbeddedExpression>();
+    List<AngularMoustacheXmlExpression> expressions = [];
     ht.Token token = node.attributeEnd;
     ht.Token endToken = node.endToken;
     bool inChild = false;
@@ -8159,10 +8997,17 @@
     _injectedLibraries.add(typeLibrary);
   }
 
-  void resolveExpressions(List<ht.EmbeddedExpression> expressions) {
-    for (ht.EmbeddedExpression embeddedExpression in expressions) {
-      Expression expression = embeddedExpression.expression;
-      resolveNode(expression);
+  void resolveExpression2(AngularXmlExpression angularXmlExpression) {
+    AngularExpression angularExpression = angularXmlExpression.expression;
+    resolveExpression(angularExpression);
+  }
+
+  void resolveExpressions(List<ht.XmlExpression> expressions) {
+    for (ht.XmlExpression xmlExpression in expressions) {
+      if (xmlExpression is AngularXmlExpression) {
+        AngularXmlExpression angularXmlExpression = xmlExpression;
+        resolveExpression2(angularXmlExpression);
+      }
     }
   }
 
@@ -8179,6 +9024,10 @@
     // add built-in processors
     _processors.add(NgModelProcessor.INSTANCE);
     // _processors.add(NgRepeatProcessor.INSTANCE);
+    // add element's libraries
+    for (AngularElement angularElement in angularElements) {
+      _injectedLibraries.add(angularElement.library);
+    }
     // add accessible processors
     for (AngularElement angularElement in angularElements) {
       NgProcessor processor = createProcessor(angularElement);
@@ -8188,17 +9037,18 @@
     }
     // prepare Dart library
     createLibraryElement();
-    _unit.compilationUnitElement = _libraryElement.definingCompilationUnit;
+    (_unit.element as HtmlElementImpl).angularCompilationUnit = _unitElement;
     // prepare Dart resolver
     createResolver();
-    // may be resolving component template
-    LocalVariableElementImpl componentVariable = null;
+    // maybe resolving component template
     if (component != null) {
-      ClassElement componentClassElement = component.enclosingElement as ClassElement;
-      InterfaceType componentType = componentClassElement.type;
-      componentVariable = createLocalVariable2(componentType, component.name);
-      defineTopVariable(componentVariable);
-      componentVariable.toolkitObjects = <AngularElement> [component];
+      defineTopElementVariable(component);
+    }
+    // define filters
+    for (AngularElement angularElement in angularElements) {
+      if (angularElement is AngularFilterElement) {
+        defineTopElementVariable(angularElement);
+      }
     }
     // run this HTML visitor
     _unit.accept(this);
@@ -8218,6 +9068,20 @@
     }
   }
 
+  List<Token> splitAtBar(Token token) {
+    List<Token> tokens = [];
+    tokens.add(token);
+    while (token.type != TokenType.EOF) {
+      if (identical(token.type, TokenType.BAR)) {
+        tokens.add(token);
+        Token eofToken = new Token(TokenType.EOF, 0);
+        token.previous.setNext(eofToken);
+      }
+      token = token.next;
+    }
+    return tokens;
+  }
+
   /**
    * The "ng-model" directive is special, it contributes to the top-level name scope. These models
    * can be used before actual "ng-model" attribute in HTML. So, we need to define them once we
@@ -8255,6 +9119,108 @@
 }
 
 /**
+ * Implementation of [AngularXmlExpression] for an [AngularExpression] enclosed between
+ * <code>{{</code> and <code>}}</code>.
+ */
+class AngularMoustacheXmlExpression extends AngularXmlExpression {
+  static int OPENING_DELIMITER_CHAR = 0x7B;
+
+  static int CLOSING_DELIMITER_CHAR = 0x7D;
+
+  static String OPENING_DELIMITER = "{{";
+
+  static String CLOSING_DELIMITER = "}}";
+
+  static int OPENING_DELIMITER_LENGTH = OPENING_DELIMITER.length;
+
+  static int CLOSING_DELIMITER_LENGTH = CLOSING_DELIMITER.length;
+
+  /**
+   * The offset of the first character of the opening delimiter.
+   */
+  int _openingOffset = 0;
+
+  /**
+   * The offset of the first character of the closing delimiter.
+   */
+  int _closingOffset = 0;
+
+  AngularMoustacheXmlExpression(int openingOffset, int closingOffset, AngularExpression expression) : super(expression) {
+    this._openingOffset = openingOffset;
+    this._closingOffset = closingOffset;
+  }
+
+  int get end => _closingOffset + CLOSING_DELIMITER_LENGTH;
+
+  int get length => _closingOffset + CLOSING_DELIMITER_LENGTH - _openingOffset;
+
+  int get offset => _openingOffset;
+}
+
+/**
+ * Implementation of [AngularXmlExpression] for an [AngularExpression] embedded without
+ * any wrapping characters.
+ */
+class AngularRawXmlExpression extends AngularXmlExpression {
+  AngularRawXmlExpression(AngularExpression expression) : super(expression);
+
+  int get end => expression.end;
+
+  int get length => expression.length;
+
+  int get offset => expression.offset;
+}
+
+/**
+ * Abstract Angular specific [XmlExpression].
+ */
+abstract class AngularXmlExpression extends ht.XmlExpression {
+  /**
+   * The expression that is enclosed between the delimiters.
+   */
+  final AngularExpression expression;
+
+  AngularXmlExpression(this.expression);
+
+  ht.XmlExpression_Reference getReference(int offset) {
+    // main expression
+    ht.XmlExpression_Reference reference = getReference2(expression.expression, offset);
+    if (reference != null) {
+      return reference;
+    }
+    // filters
+    for (AngularFilterNode filter in expression.filters) {
+      // filter name
+      reference = getReference2(filter.name, offset);
+      if (reference != null) {
+        return reference;
+      }
+      // filter arguments
+      for (AngularFilterArgument filterArgument in filter.arguments) {
+        reference = getReference2(filterArgument.expression, offset);
+        if (reference != null) {
+          return reference;
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
+   * If the given [ASTNode] has an [Element] at the given offset, then returns
+   * [Reference] with this [Element].
+   */
+  ht.XmlExpression_Reference getReference2(ASTNode root, int offset) {
+    ASTNode node = new NodeLocator.con1(offset).searchWithin(root);
+    if (node != null) {
+      Element element = ElementLocator.locate(node);
+      return new ht.XmlExpression_Reference(element, node.offset, node.length);
+    }
+    return null;
+  }
+}
+
+/**
  * Recursively visits [HtmlUnit] and every embedded [Expression].
  */
 abstract class ExpressionVisitor extends ht.RecursiveXmlVisitor<Object> {
@@ -8276,12 +9242,21 @@
   }
 
   /**
-   * Visits [Expression]s of the given [EmbeddedExpression]s.
+   * Visits [Expression]s of the given [XmlExpression]s.
    */
-  void visitExpressions(List<ht.EmbeddedExpression> expressions) {
-    for (ht.EmbeddedExpression embeddedExpression in expressions) {
-      Expression expression = embeddedExpression.expression;
-      visitExpression(expression);
+  void visitExpressions(List<ht.XmlExpression> expressions) {
+    for (ht.XmlExpression xmlExpression in expressions) {
+      if (xmlExpression is AngularXmlExpression) {
+        AngularXmlExpression angularXmlExpression = xmlExpression;
+        List<Expression> dartExpressions = angularXmlExpression.expression.expressions;
+        for (Expression dartExpression in dartExpressions) {
+          visitExpression(dartExpression);
+        }
+      }
+      if (xmlExpression is ht.RawXmlExpression) {
+        ht.RawXmlExpression rawXmlExpression = xmlExpression;
+        visitExpression(rawXmlExpression.expression);
+      }
     }
   }
 }
@@ -8306,8 +9281,8 @@
         attribute.element = property;
         // resolve if binding
         if (property.propertyKind != AngularPropertyKind.ATTR) {
-          Expression expression = parseExpression(resolver, attribute);
-          resolver.resolveNode(expression);
+          AngularExpression expression = parseAngularExpression(resolver, attribute);
+          resolver.resolveExpression(expression);
           setExpression(attribute, expression);
         }
       }
@@ -8368,8 +9343,8 @@
           resolver.pushNameScope();
           try {
             onNgEventDirective(resolver);
-            Expression expression = parseExpression(resolver, attribute);
-            resolver.resolveNode(expression);
+            AngularExpression expression = parseAngularExpression(resolver, attribute);
+            resolver.resolveExpression(expression);
             setExpression(attribute, expression);
           } finally {
             resolver.popNameScope();
@@ -8396,31 +9371,46 @@
  * [NgDirectiveProcessor] describes any <code>NgDirective</code> annotation instance.
  */
 abstract class NgDirectiveProcessor extends NgProcessor {
-  static ht.EmbeddedExpression newEmbeddedExpression(Expression e) => new ht.EmbeddedExpression(e.offset, e, e.end);
+  static AngularRawXmlExpression newAngularRawXmlExpression(AngularExpression e) => new AngularRawXmlExpression(e);
 
-  Expression parseExpression(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
-    int offset = attribute.valueToken.offset + 1;
-    String value = attribute.text;
-    Token token = resolver.scanDart(value, 0, value.length, offset);
-    return resolver.parseExpression3(token);
+  static ht.RawXmlExpression newRawXmlExpression(Expression e) => new ht.RawXmlExpression(e);
+
+  AngularExpression parseAngularExpression(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
+    Token token = scanAttribute(resolver, attribute);
+    return resolver.parseAngularExpression3(token);
+  }
+
+  Expression parseDartExpression(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
+    Token token = scanAttribute(resolver, attribute);
+    return resolver.parseDartExpression3(token);
+  }
+
+  /**
+   * Sets single [AngularExpression] for [XmlAttributeNode].
+   */
+  void setExpression(ht.XmlAttributeNode attribute, AngularExpression expression) {
+    setExpression3(attribute, newAngularRawXmlExpression(expression));
   }
 
   /**
    * Sets single [Expression] for [XmlAttributeNode].
    */
-  void setExpression(ht.XmlAttributeNode attribute, Expression expression) {
-    attribute.expressions = <ht.EmbeddedExpression> [newEmbeddedExpression(expression)];
+  void setExpression2(ht.XmlAttributeNode attribute, Expression expression) {
+    setExpression3(attribute, newRawXmlExpression(expression));
   }
 
-  /**
-   * Sets [Expression]s for [XmlAttributeNode].
-   */
-  void setExpressions(ht.XmlAttributeNode attribute, List<Expression> expressions) {
-    List<ht.EmbeddedExpression> embExpressions = [];
-    for (Expression expression in expressions) {
-      embExpressions.add(newEmbeddedExpression(expression));
-    }
-    attribute.expressions = new List.from(embExpressions);
+  void setExpressions(ht.XmlAttributeNode attribute, List<ht.XmlExpression> xmlExpressions) {
+    attribute.expressions = new List.from(xmlExpressions);
+  }
+
+  Token scanAttribute(AngularHtmlUnitResolver resolver, ht.XmlAttributeNode attribute) {
+    int offset = attribute.valueToken.offset + 1;
+    String value = attribute.text;
+    return resolver.scanDart(value, 0, value.length, offset);
+  }
+
+  void setExpression3(ht.XmlAttributeNode attribute, ht.XmlExpression xmlExpression) {
+    attribute.expressions = <ht.XmlExpression> [xmlExpression];
   }
 }
 
@@ -8434,7 +9424,7 @@
 
   void apply(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
     ht.XmlAttributeNode attribute = node.getAttribute(_NG_MODEL);
-    Expression expression = parseExpression(resolver, attribute);
+    Expression expression = parseDartExpression(resolver, attribute);
     // identifiers have been already handled by "apply top"
     if (expression is SimpleIdentifier) {
       return;
@@ -8442,7 +9432,7 @@
     // resolve
     resolver.resolveNode(expression);
     // remember expression
-    setExpression(attribute, expression);
+    setExpression2(attribute, expression);
   }
 
   bool canApply(ht.XmlTagNode node) => node.getAttribute(_NG_MODEL) != null;
@@ -8453,7 +9443,7 @@
    */
   void applyTopDeclarations(AngularHtmlUnitResolver resolver, ht.XmlTagNode node) {
     ht.XmlAttributeNode attribute = node.getAttribute(_NG_MODEL);
-    Expression expression = parseExpression(resolver, attribute);
+    Expression expression = parseDartExpression(resolver, attribute);
     // if not identifier, then not a top-level model, delay until "apply"
     if (expression is! SimpleIdentifier) {
       return;
@@ -8466,7 +9456,7 @@
     // remember expression
     identifier.staticElement = element;
     identifier.staticType = type;
-    setExpression(attribute, identifier);
+    setExpression2(attribute, identifier);
   }
 }
 
@@ -8642,6 +9632,15 @@
   E visitResolveAngularComponentTemplateTask(ResolveAngularComponentTemplateTask task);
 
   /**
+   * Visit a [ResolveAngularEntryHtmlTask].
+   *
+   * @param task the task to be visited
+   * @return the result of visiting the task
+   * @throws AnalysisException if the visitor throws an exception for some reason
+   */
+  E visitResolveAngularEntryHtmlTask(ResolveAngularEntryHtmlTask task);
+
+  /**
    * Visit a [ResolveDartDependenciesTask].
    *
    * @param task the task to be visited
@@ -8907,7 +9906,7 @@
       return;
     }
     // Produce an updated token stream
-    CharacterReader reader = new CharSequenceReader(new CharSequence(cache.newContents));
+    CharacterReader reader = new CharSequenceReader(cache.newContents);
     BooleanErrorListener errorListener = new BooleanErrorListener();
     IncrementalScanner scanner = new IncrementalScanner(cache.source, reader, errorListener);
     scanner.rescan(cache.resolvedUnit.beginToken, cache.offset, cache.oldLength, cache.newLength);
@@ -9097,15 +10096,7 @@
 
   Source_ContentReceiver_ParseDartTask_internalPerform(this.ParseDartTask_this, this.errorListener, this.token);
 
-  void accept(CharBuffer contents, int modificationTime) {
-    doScan(contents, modificationTime);
-  }
-
-  void accept2(String contents, int modificationTime) {
-    doScan(new CharSequence(contents), modificationTime);
-  }
-
-  void doScan(CharSequence contents, int modificationTime) {
+  void accept(String contents, int modificationTime) {
     ParseDartTask_this._modificationTime = modificationTime;
     TimeCounter_TimeCounterHandle timeCounterScan = PerformanceStatistics.scan.start();
     try {
@@ -9301,9 +10292,9 @@
   AngularComponentElement _component;
 
   /**
-   * All Angular elements accessible in the component library.
+   * The Angular application to resolve in context of.
    */
-  List<AngularElement> _angularElements;
+  AngularApplicationInfo _application;
 
   /**
    * The source to be resolved.
@@ -9331,11 +10322,11 @@
    * @param context the context in which the task is to be performed
    * @param source the source to be resolved
    * @param component the component that uses this HTML template, not `null`
-   * @param angularElements all Angular elements accessible in the component library
+   * @param application the Angular application to resolve in context of
    */
-  ResolveAngularComponentTemplateTask(InternalAnalysisContext context, this.source, AngularComponentElement component, List<AngularElement> angularElements) : super(context) {
+  ResolveAngularComponentTemplateTask(InternalAnalysisContext context, this.source, AngularComponentElement component, AngularApplicationInfo application) : super(context) {
     this._component = component;
-    this._angularElements = angularElements;
+    this._application = application;
   }
 
   accept(AnalysisTaskVisitor visitor) => visitor.visitResolveAngularComponentTemplateTask(this);
@@ -9360,7 +10351,7 @@
   String get taskDescription => "resolving Angular template ${source}";
 
   void internalPerform() {
-    ResolvableHtmlUnit resolvableHtmlUnit = context.computeResolvableHtmlUnit(source);
+    ResolvableHtmlUnit resolvableHtmlUnit = context.computeResolvableAngularComponentHtmlUnit(source);
     ht.HtmlUnit unit = resolvableHtmlUnit.compilationUnit;
     if (unit == null) {
       throw new AnalysisException.con1("Internal error: computeResolvableHtmlUnit returned a value without a parsed HTML unit");
@@ -9371,7 +10362,100 @@
     LineInfo lineInfo = context.getLineInfo(source);
     // do resolve
     AngularHtmlUnitResolver resolver = new AngularHtmlUnitResolver(context, errorListener, source, lineInfo, unit);
-    resolver.resolveComponentTemplate(_angularElements, _component);
+    resolver.resolveComponentTemplate(_application, _component);
+    // remember errors
+    _resolutionErrors = errorListener.getErrors2(source);
+    // remember resolved unit
+    _resolvedUnit = unit;
+  }
+}
+
+/**
+ * Instances of the class `ResolveAngularEntryHtmlTask` resolve a specific HTML file as an
+ * Angular entry point.
+ */
+class ResolveAngularEntryHtmlTask extends AnalysisTask {
+  /**
+   * The source to be resolved.
+   */
+  final Source source;
+
+  /**
+   * The Angular application to resolve in context of.
+   */
+  AngularApplicationInfo _application;
+
+  /**
+   * The time at which the contents of the source were last modified.
+   */
+  int _modificationTime = -1;
+
+  /**
+   * The [HtmlUnit] that was resolved by this task.
+   */
+  ht.HtmlUnit _resolvedUnit;
+
+  /**
+   * The element produced by resolving the source.
+   */
+  HtmlElement _element = null;
+
+  /**
+   * The resolution errors that were discovered while resolving the source.
+   */
+  List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
+
+  /**
+   * Initialize a newly created task to perform analysis within the given context.
+   *
+   * @param context the context in which the task is to be performed
+   * @param source the source to be resolved
+   * @param application the Angular application to resolve in context of
+   */
+  ResolveAngularEntryHtmlTask(InternalAnalysisContext context, this.source, AngularApplicationInfo application) : super(context) {
+    this._application = application;
+  }
+
+  accept(AnalysisTaskVisitor visitor) => visitor.visitResolveAngularEntryHtmlTask(this);
+
+  HtmlElement get element => _element;
+
+  /**
+   * Return the time at which the contents of the source that was parsed were last modified, or a
+   * negative value if the task has not yet been performed or if an exception occurred.
+   *
+   * @return the time at which the contents of the source that was parsed were last modified
+   */
+  int get modificationTime => _modificationTime;
+
+  List<AnalysisError> get resolutionErrors => _resolutionErrors;
+
+  /**
+   * Return the [HtmlUnit] that was resolved by this task.
+   *
+   * @return the [HtmlUnit] that was resolved by this task
+   */
+  ht.HtmlUnit get resolvedUnit => _resolvedUnit;
+
+  String get taskDescription {
+    if (source == null) {
+      return "resolve as Angular entry point null source";
+    }
+    return "resolve as Angular entry point ${source.fullName}";
+  }
+
+  void internalPerform() {
+    ResolvableHtmlUnit resolvableHtmlUnit = context.computeResolvableAngularComponentHtmlUnit(source);
+    ht.HtmlUnit unit = resolvableHtmlUnit.compilationUnit;
+    if (unit == null) {
+      throw new AnalysisException.con1("Internal error: computeResolvableHtmlUnit returned a value without a parsed HTML unit");
+    }
+    _modificationTime = resolvableHtmlUnit.modificationTime;
+    // prepare for resolution
+    RecordingErrorListener errorListener = new RecordingErrorListener();
+    LineInfo lineInfo = context.getLineInfo(source);
+    // do resolve
+    new AngularHtmlUnitResolver(context, errorListener, source, lineInfo, unit).resolveEntryPoint(_application);
     // remember errors
     _resolutionErrors = errorListener.getErrors2(source);
     // remember resolved unit
@@ -9750,6 +10834,16 @@
   List<AnalysisError> _resolutionErrors = AnalysisError.NO_ERRORS;
 
   /**
+   * The flag that says is this unit is an Angular application.
+   */
+  bool _isAngularApplication2 = false;
+
+  /**
+   * The Angular application information, maybe `null`
+   */
+  AngularApplicationInfo _angularApplication;
+
+  /**
    * Initialize a newly created task to perform analysis within the given context.
    *
    * @param context the context in which the task is to be performed
@@ -9759,6 +10853,12 @@
 
   accept(AnalysisTaskVisitor visitor) => visitor.visitResolveHtmlTask(this);
 
+  /**
+   * Returns the [AngularApplicationInfo] for the Web application with this Angular entry
+   * point, maybe `null` if not an Angular entry point.
+   */
+  AngularApplicationInfo get angularApplication => _angularApplication;
+
   HtmlElement get element => _element;
 
   /**
@@ -9778,6 +10878,11 @@
    */
   ht.HtmlUnit get resolvedUnit => _resolvedUnit;
 
+  /**
+   * Returns `true` if analyzed unit is an Angular application.
+   */
+  bool get isAngularApplication => _isAngularApplication2;
+
   String get taskDescription {
     if (source == null) {
       return "resolve as html null source";
@@ -9795,11 +10900,13 @@
     // build standard HTML element
     HtmlUnitBuilder builder = new HtmlUnitBuilder(context);
     _element = builder.buildHtmlElement2(source, _modificationTime, unit);
-    // resolve toolkit-specific features
+    RecordingErrorListener errorListener = builder.errorListener;
     LineInfo lineInfo = context.getLineInfo(source);
-    new AngularHtmlUnitResolver(context, builder.errorListener, source, lineInfo, unit).resolveEntryPoint();
+    // try to resolve as an Angular entry point
+    _isAngularApplication2 = AngularHtmlUnitResolver.hasAngularAnnotation(unit);
+    _angularApplication = new AngularHtmlUnitResolver(context, errorListener, source, lineInfo, unit).calculateAngularApplication();
     // record all resolution errors
-    _resolutionErrors = builder.errorListener.getErrors2(source);
+    _resolutionErrors = errorListener.getErrors2(source);
     // remember resolved unit
     _resolvedUnit = unit;
   }
@@ -9832,13 +10939,6 @@
   void logError2(String message, Exception exception);
 
   /**
-   * Log the given exception as one representing an error.
-   *
-   * @param exception the exception being logged
-   */
-  void logError3(Exception exception);
-
-  /**
    * Log the given informational message.
    *
    * @param message an explanation of why the error occurred or what it means
@@ -9865,9 +10965,6 @@
   void logError2(String message, Exception exception) {
   }
 
-  void logError3(Exception exception) {
-  }
-
   void logInformation(String message) {
   }
 
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index 31618d8..70408c6 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -143,7 +143,7 @@
 class AngularCode extends Enum<AngularCode> implements ErrorCode {
   static final AngularCode CANNOT_PARSE_SELECTOR = new AngularCode.con1('CANNOT_PARSE_SELECTOR', 0, "The selector '%s' cannot be parsed");
 
-  static final AngularCode INVALID_PROPERTY_KIND = new AngularCode.con1('INVALID_PROPERTY_KIND', 1, "Unknown property binding kind '%s', use one of the '@', '=>', '=>!' or '<=>'");
+  static final AngularCode INVALID_PROPERTY_KIND = new AngularCode.con2('INVALID_PROPERTY_KIND', 1, "Unknown property binding kind '%s', use one of the '@', '=>', '=>!' or '<=>'", ErrorSeverity.ERROR);
 
   static final AngularCode INVALID_PROPERTY_FIELD = new AngularCode.con1('INVALID_PROPERTY_FIELD', 2, "Unknown property field '%s'");
 
@@ -157,21 +157,17 @@
 
   static final AngularCode INVALID_REPEAT_ITEM_SYNTAX = new AngularCode.con1('INVALID_REPEAT_ITEM_SYNTAX', 7, "Item must by identifier or in '(_key_, _value_)' pair.");
 
-  static final AngularCode INVALID_URI = new AngularCode.con1('INVALID_URI', 8, "Invalid URI syntax: '%s'");
+  static final AngularCode INVALID_URI = new AngularCode.con2('INVALID_URI', 8, "Invalid URI syntax: '%s'", ErrorSeverity.ERROR);
 
-  static final AngularCode MISSING_CSS_URL = new AngularCode.con1('MISSING_CSS_URL', 9, "Argument 'cssUrl' must be provided");
+  static final AngularCode MISSING_FILTER_COLON = new AngularCode.con1('MISSING_FILTER_COLON', 9, "Missing ':' before filter argument");
 
-  static final AngularCode MISSING_FILTER_COLON = new AngularCode.con1('MISSING_FILTER_COLON', 10, "Missing ':' before filter argument");
+  static final AngularCode MISSING_NAME = new AngularCode.con1('MISSING_NAME', 10, "Argument 'name' must be provided");
 
-  static final AngularCode MISSING_NAME = new AngularCode.con1('MISSING_NAME', 11, "Argument 'name' must be provided");
+  static final AngularCode MISSING_PUBLISH_AS = new AngularCode.con1('MISSING_PUBLISH_AS', 11, "Argument 'publishAs' must be provided");
 
-  static final AngularCode MISSING_PUBLISH_AS = new AngularCode.con1('MISSING_PUBLISH_AS', 12, "Argument 'publishAs' must be provided");
+  static final AngularCode MISSING_SELECTOR = new AngularCode.con1('MISSING_SELECTOR', 12, "Argument 'selector' must be provided");
 
-  static final AngularCode MISSING_TEMPLATE_URL = new AngularCode.con1('MISSING_TEMPLATE_URL', 13, "Argument 'templateUrl' must be provided");
-
-  static final AngularCode MISSING_SELECTOR = new AngularCode.con1('MISSING_SELECTOR', 14, "Argument 'selector' must be provided");
-
-  static final AngularCode URI_DOES_NOT_EXIST = new AngularCode.con1('URI_DOES_NOT_EXIST', 15, "Target of URI does not exist: '%s'");
+  static final AngularCode URI_DOES_NOT_EXIST = new AngularCode.con1('URI_DOES_NOT_EXIST', 13, "Target of URI does not exist: '%s'");
 
   static final List<AngularCode> values = [
       CANNOT_PARSE_SELECTOR,
@@ -183,11 +179,9 @@
       INVALID_REPEAT_SYNTAX,
       INVALID_REPEAT_ITEM_SYNTAX,
       INVALID_URI,
-      MISSING_CSS_URL,
       MISSING_FILTER_COLON,
       MISSING_NAME,
       MISSING_PUBLISH_AS,
-      MISSING_TEMPLATE_URL,
       MISSING_SELECTOR,
       URI_DOES_NOT_EXIST];
 
@@ -221,11 +215,11 @@
 
   String get correction => null;
 
-  ErrorSeverity get errorSeverity => _severity;
+  ErrorSeverity get errorSeverity => ErrorSeverity.INFO;
 
   String get message => _message;
 
-  ErrorType get type => ErrorType.TOOLKIT;
+  ErrorType get type => ErrorType.ANGULAR;
 }
 
 /**
@@ -756,6 +750,14 @@
    */
   static final HintCode UNUSED_IMPORT = new HintCode.con1('UNUSED_IMPORT', 22, "Unused import");
 
+  /**
+   * Hint for cases where the source expects a method or function to return a non-void result, but
+   * the method or function signature returns void.
+   *
+   * @param name the name of the method or function that returns void
+   */
+  static final HintCode USE_OF_VOID_RESULT = new HintCode.con1('USE_OF_VOID_RESULT', 23, "The result of '%s' is being used, even though it is declared to be 'void'");
+
   static final List<HintCode> values = [
       DEAD_CODE,
       DEAD_CODE_CATCH_FOLLOWING_CATCH,
@@ -779,7 +781,8 @@
       UNNECESSARY_CAST,
       UNNECESSARY_TYPE_CHECK_FALSE,
       UNNECESSARY_TYPE_CHECK_TRUE,
-      UNUSED_IMPORT];
+      UNUSED_IMPORT,
+      USE_OF_VOID_RESULT];
 
   /**
    * The template used to create the message to be displayed for this error.
@@ -906,9 +909,9 @@
   static final ErrorType SYNTACTIC_ERROR = new ErrorType('SYNTACTIC_ERROR', 6, ErrorSeverity.ERROR);
 
   /**
-   * Toolkit specific semantic problems.
+   * Angular specific semantic problems.
    */
-  static final ErrorType TOOLKIT = new ErrorType('TOOLKIT', 7, ErrorSeverity.INFO);
+  static final ErrorType ANGULAR = new ErrorType('ANGULAR', 7, ErrorSeverity.INFO);
 
   static final List<ErrorType> values = [
       TODO,
@@ -918,7 +921,7 @@
       STATIC_WARNING,
       STATIC_TYPE_WARNING,
       SYNTACTIC_ERROR,
-      TOOLKIT];
+      ANGULAR];
 
   /**
    * The severity of this type of error.
diff --git a/pkg/analyzer/lib/src/generated/html.dart b/pkg/analyzer/lib/src/generated/html.dart
index 9a24e05..2d511c1 100644
--- a/pkg/analyzer/lib/src/generated/html.dart
+++ b/pkg/analyzer/lib/src/generated/html.dart
@@ -16,7 +16,7 @@
 import 'parser.dart' show Parser;
 import 'ast.dart';
 import 'element.dart';
-import 'engine.dart' show AnalysisEngine, AngularHtmlUnitResolver;
+import 'engine.dart' show AnalysisEngine, AngularHtmlUnitResolver, ExpressionVisitor;
 
 /**
  * Instances of the class `Token` represent a token that was scanned from the input. Each
@@ -141,38 +141,28 @@
 }
 
 /**
- * Instances of the class `EmbeddedExpression` represent an expression enclosed between
- * <code>{{</code> and <code>}}</code> delimiters.
+ * Implementation of [XmlExpression] for an [Expression] embedded without any wrapping
+ * characters.
  */
-class EmbeddedExpression {
-  /**
-   * The offset of the first character of the opening delimiter.
-   */
-  final int openingOffset;
-
-  /**
-   * The expression that is enclosed between the delimiters.
-   */
+class RawXmlExpression extends XmlExpression {
   final Expression expression;
 
-  /**
-   * The offset of the first character of the closing delimiter.
-   */
-  final int closingOffset;
+  RawXmlExpression(this.expression);
 
-  /**
-   * An empty array of embedded expressions.
-   */
-  static List<EmbeddedExpression> EMPTY_ARRAY = new List<EmbeddedExpression>(0);
+  int get end => expression.end;
 
-  /**
-   * Initialize a newly created embedded expression to represent the given expression.
-   *
-   * @param openingOffset the offset of the first character of the opening delimiter
-   * @param expression the expression that is enclosed between the delimiters
-   * @param closingOffset the offset of the first character of the closing delimiter
-   */
-  EmbeddedExpression(this.openingOffset, this.expression, this.closingOffset);
+  int get length => expression.length;
+
+  int get offset => expression.offset;
+
+  XmlExpression_Reference getReference(int offset) {
+    ASTNode node = new NodeLocator.con1(offset).searchWithin(expression);
+    if (node != null) {
+      Element element = ElementLocator.locate(node);
+      return new XmlExpression_Reference(element, node.offset, node.length);
+    }
+    return null;
+  }
 }
 
 /**
@@ -296,7 +286,8 @@
     }
     List<Expression> result = [null];
     try {
-      htmlUnit.accept(new RecursiveXmlVisitor_HtmlUnitUtils_getExpression(offset, result));
+      // TODO(scheglov) this code is very Angular specific
+      htmlUnit.accept(new ExpressionVisitor_HtmlUnitUtils_getExpression(offset, result));
     } on HtmlUnitUtils_FoundExpressionError catch (e) {
       return result[0];
     }
@@ -361,31 +352,18 @@
   }
 }
 
-class RecursiveXmlVisitor_HtmlUnitUtils_getExpression extends RecursiveXmlVisitor<Object> {
+class ExpressionVisitor_HtmlUnitUtils_getExpression extends ExpressionVisitor {
   int offset = 0;
 
   List<Expression> result;
 
-  RecursiveXmlVisitor_HtmlUnitUtils_getExpression(this.offset, this.result) : super();
+  ExpressionVisitor_HtmlUnitUtils_getExpression(this.offset, this.result) : super();
 
-  Object visitXmlAttributeNode(XmlAttributeNode node) {
-    findExpression(offset, result, node.expressions);
-    return super.visitXmlAttributeNode(node);
-  }
-
-  Object visitXmlTagNode(XmlTagNode node) {
-    findExpression(offset, result, node.expressions);
-    return super.visitXmlTagNode(node);
-  }
-
-  void findExpression(int offset, List<Expression> result, List<EmbeddedExpression> expressions) {
-    for (EmbeddedExpression embeddedExpression in expressions) {
-      Expression expression = embeddedExpression.expression;
-      Expression at = HtmlUnitUtils.getExpressionAt(expression, offset);
-      if (at != null) {
-        result[0] = at;
-        throw new HtmlUnitUtils_FoundExpressionError();
-      }
+  void visitExpression(Expression expression) {
+    Expression at = HtmlUnitUtils.getExpressionAt(expression, offset);
+    if (at != null) {
+      result[0] = at;
+      throw new HtmlUnitUtils_FoundExpressionError();
     }
   }
 }
@@ -651,7 +629,7 @@
     XmlNode current = newParent;
     while (current != null) {
       if (identical(current, this)) {
-        AnalysisEngine.instance.logger.logError3(new IllegalArgumentException(buildRecursiveStructureMessage(newParent)));
+        AnalysisEngine.instance.logger.logError2("Circular structure while setting an XML node's parent", new IllegalArgumentException(buildRecursiveStructureMessage(newParent)));
         return;
       }
       current = current.parent;
@@ -1069,7 +1047,7 @@
     return -1;
   }
 
-  String getString(int start, int endDelta) => _string.substring(start, _charOffset + 1 + endDelta);
+  String getString(int start, int endDelta) => _string.substring(start, _charOffset + 1 + endDelta).toString();
 
   int peek() {
     if (_charOffset + 1 < _stringLength) {
@@ -1080,60 +1058,6 @@
 }
 
 /**
- * Instances of the class `CharBufferScanner` implement a scanner that reads from a character
- * buffer. The scanning logic is in the superclass.
- *
- * @coverage dart.engine.html
- */
-class CharBufferScanner extends AbstractScanner {
-  /**
-   * The buffer from which characters will be read.
-   */
-  CharSequence _buffer;
-
-  /**
-   * The number of characters in the buffer.
-   */
-  int _bufferLength = 0;
-
-  /**
-   * The index of the last character that was read.
-   */
-  int _charOffset = 0;
-
-  /**
-   * Initialize a newly created scanner to scan the characters in the given character buffer.
-   *
-   * @param source the source being scanned
-   * @param buffer the buffer from which characters will be read
-   */
-  CharBufferScanner(Source source, CharSequence buffer) : super(source) {
-    this._buffer = buffer;
-    this._bufferLength = buffer.length();
-    this._charOffset = -1;
-  }
-
-  int get offset => _charOffset;
-
-  int advance() {
-    if (++_charOffset < _bufferLength) {
-      return _buffer.charAt(_charOffset);
-    }
-    _charOffset = _bufferLength;
-    return -1;
-  }
-
-  String getString(int start, int endDelta) => _buffer.subSequence(start, _charOffset + 1 + endDelta).toString();
-
-  int peek() {
-    if (_charOffset + 1 < _bufferLength) {
-      return _buffer.charAt(_charOffset + 1);
-    }
-    return -1;
-  }
-}
-
-/**
  * Instances of the class `ToSourceVisitor` write a source representation of a visited XML
  * node (and all of it's children) to a writer.
  *
@@ -1288,7 +1212,7 @@
 
   Token _value;
 
-  List<EmbeddedExpression> expressions = EmbeddedExpression.EMPTY_ARRAY;
+  List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
 
   /**
    * Construct a new instance representing an XML attribute.
@@ -1367,57 +1291,6 @@
 }
 
 /**
- * Instances of the class `EmbeddedDartVisitor` implement a recursive visitor for HTML files
- * that will invoke another visitor on all embedded dart scripts and expressions.
- */
-class EmbeddedDartVisitor<R> implements XmlVisitor<R> {
-  /**
-   * The visitor used to visit embedded Dart code.
-   */
-  ASTVisitor<R> _dartVisitor;
-
-  /**
-   * Initialize a newly created visitor to visit all of the nodes in an HTML structure and to use
-   * the given visitor to visit all of the nodes representing any embedded scripts or expressions.
-   *
-   * @param dartVisitor the visitor used to visit embedded Dart code
-   */
-  EmbeddedDartVisitor(ASTVisitor<R> dartVisitor) {
-    this._dartVisitor = dartVisitor;
-  }
-
-  R visitHtmlScriptTagNode(HtmlScriptTagNode node) {
-    node.visitChildren(this);
-    CompilationUnit script = node.script;
-    if (script != null) {
-      script.accept(_dartVisitor);
-    }
-    return null;
-  }
-
-  R visitHtmlUnit(HtmlUnit node) {
-    node.visitChildren(this);
-    return null;
-  }
-
-  R visitXmlAttributeNode(XmlAttributeNode node) {
-    node.visitChildren(this);
-    for (EmbeddedExpression expression in node.expressions) {
-      expression.expression.accept(_dartVisitor);
-    }
-    return null;
-  }
-
-  R visitXmlTagNode(XmlTagNode node) {
-    node.visitChildren(this);
-    for (EmbeddedExpression expression in node.expressions) {
-      expression.expression.accept(_dartVisitor);
-    }
-    return null;
-  }
-}
-
-/**
  * The interface `XmlVisitor` defines the behavior of objects that can be used to visit an
  * [XmlNode] structure.
  *
@@ -1434,6 +1307,65 @@
 }
 
 /**
+ * Instances of the class `XmlExpression` represent an abstract expression embedded into
+ * [XmlNode].
+ */
+abstract class XmlExpression {
+  /**
+   * An empty array of expressions.
+   */
+  static List<XmlExpression> EMPTY_ARRAY = new List<XmlExpression>(0);
+
+  /**
+   * Check if the given offset belongs to the expression's source range.
+   */
+  bool contains(int offset) => this.offset <= offset && offset < end;
+
+  /**
+   * Return the offset of the character immediately following the last character of this
+   * expression's source range. This is equivalent to `getOffset() + getLength()`.
+   *
+   * @return the offset of the character just past the expression's source range
+   */
+  int get end;
+
+  /**
+   * Return the number of characters in the expression's source range.
+   */
+  int get length;
+
+  /**
+   * Return the offset of the first character in the expression's source range.
+   */
+  int get offset;
+
+  /**
+   * Return the [Reference] at the given offset.
+   *
+   * @param offset the offset from the beginning of the file
+   * @return the [Reference] at the given offset, maybe `null`
+   */
+  XmlExpression_Reference getReference(int offset);
+}
+
+/**
+ * The reference to the [Element].
+ */
+class XmlExpression_Reference {
+  Element element;
+
+  int offset = 0;
+
+  int length = 0;
+
+  XmlExpression_Reference(Element element, int offset, int length) {
+    this.element = element;
+    this.offset = offset;
+    this.length = length;
+  }
+}
+
+/**
  * Instances of `HtmlScanner` receive and scan HTML content from a [Source].<br/>
  * For example, the following code scans HTML source and returns the result:
  *
@@ -1477,14 +1409,7 @@
     this._source = source;
   }
 
-  void accept(CharBuffer contents, int modificationTime) {
-    this._modificationTime = modificationTime;
-    _scanner = new CharBufferScanner(_source, contents);
-    _scanner.passThroughElements = _SCRIPT_TAG;
-    _token = _scanner.tokenize();
-  }
-
-  void accept2(String contents, int modificationTime) {
+  void accept(String contents, int modificationTime) {
     this._modificationTime = modificationTime;
     _scanner = new StringScanner(_source, contents);
     _scanner.passThroughElements = _SCRIPT_TAG;
@@ -1838,7 +1763,7 @@
   /**
    * The expressions that are embedded in the tag's content.
    */
-  List<EmbeddedExpression> expressions = EmbeddedExpression.EMPTY_ARRAY;
+  List<XmlExpression> expressions = XmlExpression.EMPTY_ARRAY;
 
   /**
    * Construct a new instance representing an XML or HTML element
@@ -2056,7 +1981,7 @@
    */
   static sc.Token scanDartSource(Source source, LineInfo lineInfo, String contents, int contentOffset, AnalysisErrorListener errorListener) {
     LineInfo_Location location = lineInfo.getLocation(contentOffset);
-    sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(new CharSequence(contents), contentOffset), errorListener);
+    sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(contents, contentOffset), errorListener);
     scanner.setSourceStart(location.lineNumber, location.columnNumber);
     return scanner.tokenize();
   }
@@ -2106,7 +2031,7 @@
       String contents = tagNode.content;
       int contentOffset = attributeEnd.end;
       LineInfo_Location location = _lineInfo.getLocation(contentOffset);
-      sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(new CharSequence(contents), contentOffset), _errorListener);
+      sc.Scanner scanner = new sc.Scanner(source, new sc.SubSequenceReader(contents, contentOffset), _errorListener);
       scanner.setSourceStart(location.lineNumber, location.columnNumber);
       sc.Token firstToken = scanner.tokenize();
       Parser parser = new Parser(source, _errorListener);
@@ -2168,12 +2093,6 @@
   List<XmlTagNode> _tagNodes;
 
   /**
-   * The element associated with Dart pieces in this HTML unit or `null` if the receiver is
-   * not resolved.
-   */
-  CompilationUnitElement compilationUnitElement;
-
-  /**
    * Construct a new instance representing the content of an HTML file.
    *
    * @param beginToken the first token in the file (not `null`)
diff --git a/pkg/analyzer/lib/src/generated/index.dart b/pkg/analyzer/lib/src/generated/index.dart
index be2d4f8..12d012ac 100644
--- a/pkg/analyzer/lib/src/generated/index.dart
+++ b/pkg/analyzer/lib/src/generated/index.dart
@@ -15,7 +15,7 @@
 import 'ast.dart';
 import 'element.dart';
 import 'resolver.dart' show Namespace, NamespaceBuilder;
-import 'engine.dart' show AnalysisEngine, AnalysisContext, InstrumentedAnalysisContextImpl, AngularHtmlUnitResolver;
+import 'engine.dart';
 import 'html.dart' as ht;
 
 /**
@@ -121,7 +121,13 @@
    */
   static Source getLibrarySourceOrNull(Element element) {
     LibraryElement library = element.library;
-    return library != null ? library.source : null;
+    if (library == null) {
+      return null;
+    }
+    if (library.isAngularHtml) {
+      return null;
+    }
+    return library.source;
   }
 
   /**
@@ -216,17 +222,7 @@
       libraryToUnits[library] = newParts;
     }
     // remember libraries in which unit is used
-    Map<Source, Set<Source>> unitToLibraries = _contextToUnitToLibraries[context];
-    if (unitToLibraries == null) {
-      unitToLibraries = {};
-      _contextToUnitToLibraries[context] = unitToLibraries;
-    }
-    Set<Source> libraries = unitToLibraries[unit];
-    if (libraries == null) {
-      libraries = new Set();
-      unitToLibraries[unit] = libraries;
-    }
-    libraries.add(library);
+    recordUnitInLibrary(context, library, unit);
     // remove locations
     removeLocations(context, library, unit);
     // remove keys
@@ -234,29 +230,38 @@
       Map<MemoryIndexStoreImpl_Source2, Set<MemoryIndexStoreImpl_ElementRelationKey>> sourceToKeys = _contextToSourceToKeys[context];
       if (sourceToKeys != null) {
         MemoryIndexStoreImpl_Source2 source2 = new MemoryIndexStoreImpl_Source2(library, unit);
-        sourceToKeys.remove(source2);
+        bool hadSource = sourceToKeys.remove(source2) != null;
+        if (hadSource) {
+          _sourceCount--;
+        }
       }
     }
     // OK, we can index
     return true;
   }
 
-  bool aboutToIndex2(AnalysisContext context, Source source) {
+  bool aboutToIndex2(AnalysisContext context, HtmlElement htmlElement) {
     context = unwrapContext(context);
     // may be already removed in other thread
     if (isRemovedContext(context)) {
       return false;
     }
     // remove locations
-    removeLocations(context, source, source);
+    Source source = htmlElement.source;
+    removeLocations(context, null, source);
     // remove keys
     {
       Map<MemoryIndexStoreImpl_Source2, Set<MemoryIndexStoreImpl_ElementRelationKey>> sourceToKeys = _contextToSourceToKeys[context];
       if (sourceToKeys != null) {
-        MemoryIndexStoreImpl_Source2 source2 = new MemoryIndexStoreImpl_Source2(source, source);
-        sourceToKeys.remove(source2);
+        MemoryIndexStoreImpl_Source2 source2 = new MemoryIndexStoreImpl_Source2(null, source);
+        bool hadSource = sourceToKeys.remove(source2) != null;
+        if (hadSource) {
+          _sourceCount--;
+        }
       }
     }
+    // remember libraries in which unit is used
+    recordUnitInLibrary(context, null, source);
     // OK, we can index
     return true;
   }
@@ -315,6 +320,7 @@
     if (element is Member) {
       element = (element as Member).baseElement;
     }
+    //    System.out.println(element + " " + relationship + " " + location);
     // prepare information
     AnalysisContext elementContext = element.context;
     AnalysisContext locationContext = location.element.context;
@@ -503,6 +509,20 @@
     _removedContexts[context] = true;
   }
 
+  void recordUnitInLibrary(AnalysisContext context, Source library, Source unit) {
+    Map<Source, Set<Source>> unitToLibraries = _contextToUnitToLibraries[context];
+    if (unitToLibraries == null) {
+      unitToLibraries = {};
+      _contextToUnitToLibraries[context] = unitToLibraries;
+    }
+    Set<Source> libraries = unitToLibraries[unit];
+    if (libraries == null) {
+      libraries = new Set();
+      unitToLibraries[unit] = libraries;
+    }
+    libraries.add(library);
+  }
+
   /**
    * Removes locations recorded in the given library/unit pair.
    */
@@ -678,12 +698,21 @@
   }
 
   /**
-   * Visits [Expression]s of the given [EmbeddedExpression]s.
+   * Visits [Expression]s of the given [XmlExpression]s.
    */
-  void visitExpressions(List<ht.EmbeddedExpression> expressions) {
-    for (ht.EmbeddedExpression embeddedExpression in expressions) {
-      Expression expression = embeddedExpression.expression;
-      visitExpression(expression);
+  void visitExpressions(List<ht.XmlExpression> expressions) {
+    for (ht.XmlExpression xmlExpression in expressions) {
+      if (xmlExpression is AngularXmlExpression) {
+        AngularXmlExpression angularXmlExpression = xmlExpression;
+        List<Expression> dartExpressions = angularXmlExpression.expression.expressions;
+        for (Expression dartExpression in dartExpressions) {
+          visitExpression(dartExpression);
+        }
+      }
+      if (xmlExpression is ht.RawXmlExpression) {
+        ht.RawXmlExpression rawXmlExpression = xmlExpression;
+        visitExpression(rawXmlExpression.expression);
+      }
     }
   }
 }
@@ -777,7 +806,7 @@
     if (unit.element == null) {
       return;
     }
-    if (unit.compilationUnitElement == null) {
+    if (unit.element.angularCompilationUnit == null) {
       return;
     }
     _queue.enqueue(new IndexHtmlUnitOperation(_store, context, unit));
@@ -1229,7 +1258,7 @@
 
   Object visitHtmlUnit(ht.HtmlUnit node) {
     _htmlUnitElement = node.element;
-    CompilationUnitElement dartUnitElement = node.compilationUnitElement;
+    CompilationUnitElement dartUnitElement = _htmlUnitElement.angularCompilationUnit;
     _indexContributor.enterScope(dartUnitElement);
     return super.visitHtmlUnit(node);
   }
@@ -1392,18 +1421,14 @@
   bool aboutToIndex(AnalysisContext context, CompilationUnitElement unitElement);
 
   /**
-   * Notifies the index store that we are going to index the given [Source].
-   *
-   * This method should be used only for a [Source] that cannot be a part of multiple
-   * libraries. Otherwise [aboutToIndex] should be
-   * used.
+   * Notifies the index store that we are going to index the given [HtmlElement].
    *
    * @param the [AnalysisContext] in which unit being indexed
-   * @param source the [Source] being indexed
+   * @param htmlElement the [HtmlElement] being indexed
    * @return `true` the given [AnalysisContext] is active, or `false` if it was
    *         removed before, so no any unit may be indexed with it
    */
-  bool aboutToIndex2(AnalysisContext context, Source source);
+  bool aboutToIndex2(AnalysisContext context, HtmlElement htmlElement);
 
   /**
    * Return the locations of the elements that have the given relationship with the given element.
@@ -2656,7 +2681,7 @@
   void performOperation() {
     {
       try {
-        bool mayIndex = _indexStore.aboutToIndex2(_context, _source);
+        bool mayIndex = _indexStore.aboutToIndex2(_context, _htmlElement);
         if (!mayIndex) {
           return;
         }
diff --git a/pkg/analyzer/lib/src/generated/java_io.dart b/pkg/analyzer/lib/src/generated/java_io.dart
index bdd7fd8..0957f27 100644
--- a/pkg/analyzer/lib/src/generated/java_io.dart
+++ b/pkg/analyzer/lib/src/generated/java_io.dart
@@ -1,7 +1,7 @@
 library java.io;
 
 import "dart:io";
-import 'java_core.dart' show JavaIOException;
+import 'java_core.dart' show JavaIOException, CharSequence;
 import 'package:path/path.dart' as pathos;
 
 class JavaSystemIO {
@@ -56,7 +56,7 @@
   static final int separatorChar = Platform.pathSeparator.codeUnitAt(0);
   String _path;
   JavaFile(String path) {
-    _path = pathos.normalize(path);
+    _path = pathos.absolute(path);
   }
   JavaFile.relative(JavaFile base, String child) {
     if (child.isEmpty) {
@@ -103,6 +103,9 @@
     }
     return false;
   }
+  bool isFile() {
+    return _newFile().existsSync();
+  }
   bool isDirectory() {
     return _newDirectory().existsSync();
   }
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 9647bf9..4c93ace 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -7,7 +7,6 @@
 
 library engine.parser;
 
-import 'dart:collection';
 import 'java_core.dart';
 import 'java_engine.dart';
 import 'instrumentation.dart';
@@ -218,7 +217,7 @@
 
   ASTNode visitAssertStatement(AssertStatement node) {
     if (identical(_oldNode, node.condition)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -232,7 +231,7 @@
       throw new InsufficientContextException();
     } else if (identical(_oldNode, node.rightHandSide)) {
       if (isCascadeAllowed(node)) {
-        return _parser.parseExpression4();
+        return _parser.parseExpression2();
       }
       return _parser.parseExpressionWithoutCascade();
     }
@@ -422,7 +421,7 @@
     if (identical(_oldNode, node.parameter)) {
       return _parser.parseNormalFormalParameter();
     } else if (identical(_oldNode, node.defaultValue)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -431,7 +430,7 @@
     if (identical(_oldNode, node.body)) {
       return _parser.parseStatement2();
     } else if (identical(_oldNode, node.condition)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -457,14 +456,14 @@
 
   ASTNode visitExpressionFunctionBody(ExpressionFunctionBody node) {
     if (identical(_oldNode, node.expression)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
 
   ASTNode visitExpressionStatement(ExpressionStatement node) {
     if (identical(_oldNode, node.expression)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -524,9 +523,9 @@
     } else if (identical(_oldNode, node.initialization)) {
       throw new InsufficientContextException();
     } else if (identical(_oldNode, node.condition)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     } else if (node.updaters.contains(_oldNode)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     } else if (identical(_oldNode, node.body)) {
       return _parser.parseStatement2();
     }
@@ -614,7 +613,7 @@
 
   ASTNode visitIfStatement(IfStatement node) {
     if (identical(_oldNode, node.condition)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     } else if (identical(_oldNode, node.thenStatement)) {
       return _parser.parseStatement2();
     } else if (identical(_oldNode, node.elseStatement)) {
@@ -649,7 +648,7 @@
     if (identical(_oldNode, node.target)) {
       throw new InsufficientContextException();
     } else if (identical(_oldNode, node.index)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -670,7 +669,7 @@
       if (node.leftBracket == null) {
         throw new InsufficientContextException();
       }
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -726,7 +725,7 @@
     if (identical(_oldNode, node.typeArguments)) {
       return _parser.parseTypeArgumentList();
     } else if (node.elements.contains(_oldNode)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -742,9 +741,9 @@
 
   ASTNode visitMapLiteralEntry(MapLiteralEntry node) {
     if (identical(_oldNode, node.key)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     } else if (identical(_oldNode, node.value)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -783,7 +782,7 @@
     if (identical(_oldNode, node.name)) {
       return _parser.parseLabel();
     } else if (identical(_oldNode, node.expression)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -806,7 +805,7 @@
 
   ASTNode visitParenthesizedExpression(ParenthesizedExpression node) {
     if (identical(_oldNode, node.expression)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -878,7 +877,7 @@
 
   ASTNode visitReturnStatement(ReturnStatement node) {
     if (identical(_oldNode, node.expression)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     }
     return notAChild(node);
   }
@@ -931,7 +930,7 @@
     if (node.labels.contains(_oldNode)) {
       return _parser.parseLabel();
     } else if (identical(_oldNode, node.expression)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     } else if (node.statements.contains(_oldNode)) {
       return _parser.parseStatement2();
     }
@@ -949,7 +948,7 @@
 
   ASTNode visitSwitchStatement(SwitchStatement node) {
     if (identical(_oldNode, node.expression)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     } else if (node.members.contains(_oldNode)) {
       throw new InsufficientContextException();
     }
@@ -963,7 +962,7 @@
   ASTNode visitThrowExpression(ThrowExpression node) {
     if (identical(_oldNode, node.expression)) {
       if (isCascadeAllowed2(node)) {
-        return _parser.parseExpression4();
+        return _parser.parseExpression2();
       }
       return _parser.parseExpressionWithoutCascade();
     }
@@ -1061,7 +1060,7 @@
 
   ASTNode visitWhileStatement(WhileStatement node) {
     if (identical(_oldNode, node.condition)) {
-      return _parser.parseExpression4();
+      return _parser.parseExpression2();
     } else if (identical(_oldNode, node.body)) {
       return _parser.parseStatement2();
     }
@@ -1415,7 +1414,7 @@
     InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseExpression");
     try {
       _currentToken = token;
-      return parseExpression4();
+      return parseExpression2();
     } finally {
       instrumentation.log();
     }
@@ -1510,9 +1509,9 @@
     // have an identifier followed by a colon.
     //
     if (matchesIdentifier() && matches4(peek(), TokenType.COLON)) {
-      return new NamedExpression(parseLabel(), parseExpression4());
+      return new NamedExpression(parseLabel(), parseExpression2());
     } else {
-      return parseExpression4();
+      return parseExpression2();
     }
   }
 
@@ -1550,7 +1549,7 @@
       if (foundNamedArgument) {
         if (!generatedError && argument is! NamedExpression) {
           // Report the error, once, but allow the arguments to be in any order in the AST.
-          reportError12(ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT, []);
+          reportError13(ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT, []);
           generatedError = true;
         }
       } else if (argument is NamedExpression) {
@@ -1610,7 +1609,7 @@
       }
       if (identical(_currentToken, statementStart)) {
         // Ensure that we are making progress and report an error if we're not.
-        reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+        reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
         advance();
       }
       statementStart = _currentToken;
@@ -1661,7 +1660,7 @@
             //
             // We appear to have a variable declaration with a type of "void".
             //
-            reportError11(ParserErrorCode.VOID_VARIABLE, returnType, []);
+            reportError12(ParserErrorCode.VOID_VARIABLE, returnType, []);
             return parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, validateModifiersForField(modifiers), returnType);
           }
         }
@@ -1672,7 +1671,7 @@
           validateModifiersForOperator(modifiers);
           return parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType);
         }
-        reportError13(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
+        reportError14(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
         return null;
       }
     } else if (matches(Keyword.GET) && matchesIdentifier2(peek())) {
@@ -1692,7 +1691,7 @@
         validateModifiersForOperator(modifiers);
         return parseOperator(commentAndMetadata, modifiers.externalKeyword, null);
       }
-      reportError13(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
+      reportError14(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
       return null;
     } else if (matches4(peek(), TokenType.PERIOD) && matchesIdentifier2(peek2(2)) && matches4(peek2(3), TokenType.OPEN_PAREN)) {
       return parseConstructor(commentAndMetadata, modifiers.externalKeyword, validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, parseSimpleIdentifier(), andAdvance, parseSimpleIdentifier(), parseFormalParameterList());
@@ -1707,7 +1706,7 @@
       return parseMethodDeclaration2(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, null, methodName, parameters);
     } else if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
       if (modifiers.constKeyword == null && modifiers.finalKeyword == null && modifiers.varKeyword == null) {
-        reportError12(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
+        reportError13(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
       }
       return parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, validateModifiersForField(modifiers), null);
     }
@@ -1742,7 +1741,7 @@
       // At this point it consists of a type name, so we'll treat it as a field declaration
       // with a missing field name and semicolon.
       //
-      reportError13(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
+      reportError14(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
       try {
         lockErrorListener();
         return parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, validateModifiersForField(modifiers), type);
@@ -1753,7 +1752,7 @@
       SimpleIdentifier methodName = parseSimpleIdentifier();
       FormalParameterList parameters = parseFormalParameterList();
       if (methodName.name == className) {
-        reportError11(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type, []);
+        reportError12(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type, []);
         return parseConstructor(commentAndMetadata, modifiers.externalKeyword, validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, methodName, null, null, parameters);
       }
       validateModifiersForGetterOrSetterOrMethod(modifiers);
@@ -1807,15 +1806,15 @@
       if ((matches(Keyword.IMPORT) || matches(Keyword.EXPORT) || matches(Keyword.LIBRARY) || matches(Keyword.PART)) && !matches4(peek(), TokenType.PERIOD) && !matches4(peek(), TokenType.LT) && !matches4(peek(), TokenType.OPEN_PAREN)) {
         Directive directive = parseDirective(commentAndMetadata);
         if (declarations.length > 0 && !directiveFoundAfterDeclaration) {
-          reportError12(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, []);
+          reportError13(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, []);
           directiveFoundAfterDeclaration = true;
         }
         if (directive is LibraryDirective) {
           if (libraryDirectiveFound) {
-            reportError12(ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES, []);
+            reportError13(ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES, []);
           } else {
             if (directives.length > 0) {
-              reportError13(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, directive.libraryToken, []);
+              reportError14(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, directive.libraryToken, []);
             }
             libraryDirectiveFound = true;
           }
@@ -1823,29 +1822,29 @@
           partDirectiveFound = true;
         } else if (partDirectiveFound) {
           if (directive is ExportDirective) {
-            reportError13(ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
+            reportError14(ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
           } else if (directive is ImportDirective) {
-            reportError13(ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
+            reportError14(ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
           }
         }
         if (directive is PartOfDirective) {
           if (partOfDirectiveFound) {
-            reportError12(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []);
+            reportError13(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []);
           } else {
             int directiveCount = directives.length;
             for (int i = 0; i < directiveCount; i++) {
-              reportError13(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directives[i].keyword, []);
+              reportError14(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directives[i].keyword, []);
             }
             partOfDirectiveFound = true;
           }
         } else {
           if (partOfDirectiveFound) {
-            reportError13(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directive.keyword, []);
+            reportError14(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directive.keyword, []);
           }
         }
         directives.add(directive);
       } else if (matches5(TokenType.SEMICOLON)) {
-        reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+        reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
         advance();
       } else {
         CompilationUnitMember member = parseCompilationUnitMember(commentAndMetadata);
@@ -1854,7 +1853,7 @@
         }
       }
       if (identical(_currentToken, memberStart)) {
-        reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+        reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
         advance();
         while (!matches5(TokenType.EOF) && !couldBeStartOfCompilationUnitMember()) {
           advance();
@@ -1920,7 +1919,7 @@
    *
    * @return the expression that was parsed
    */
-  Expression parseExpression4() {
+  Expression parseExpression2() {
     if (matches(Keyword.THROW)) {
       return parseThrowExpression();
     } else if (matches(Keyword.RETHROW)) {
@@ -1946,7 +1945,7 @@
     } else if (tokenType.isAssignmentOperator) {
       Token operator = andAdvance;
       ensureAssignable(expression);
-      return new AssignmentExpression(expression, operator, parseExpression4());
+      return new AssignmentExpression(expression, operator, parseExpression2());
     }
     return expression;
   }
@@ -2056,9 +2055,9 @@
       } else if (!optional(TokenType.COMMA)) {
         // TODO(brianwilkerson) The token is wrong, we need to recover from this case.
         if (getEndToken(leftParenthesis) != null) {
-          reportError12(ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
+          reportError13(ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
         } else {
-          reportError13(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, _currentToken.previous, []);
+          reportError14(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, _currentToken.previous, []);
           break;
         }
       }
@@ -2069,11 +2068,11 @@
       if (matches5(TokenType.OPEN_SQUARE_BRACKET)) {
         wasOptionalParameter = true;
         if (leftSquareBracket != null && !reportedMuliplePositionalGroups) {
-          reportError12(ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS, []);
+          reportError13(ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS, []);
           reportedMuliplePositionalGroups = true;
         }
         if (leftCurlyBracket != null && !reportedMixedGroups) {
-          reportError12(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
+          reportError13(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
           reportedMixedGroups = true;
         }
         leftSquareBracket = andAdvance;
@@ -2082,11 +2081,11 @@
       } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) {
         wasOptionalParameter = true;
         if (leftCurlyBracket != null && !reportedMulipleNamedGroups) {
-          reportError12(ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS, []);
+          reportError13(ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS, []);
           reportedMulipleNamedGroups = true;
         }
         if (leftSquareBracket != null && !reportedMixedGroups) {
-          reportError12(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
+          reportError13(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
           reportedMixedGroups = true;
         }
         leftCurlyBracket = andAdvance;
@@ -2100,7 +2099,7 @@
       parameters.add(parameter);
       currentParameters.add(parameter);
       if (identical(kind, ParameterKind.REQUIRED) && wasOptionalParameter) {
-        reportError11(ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter, []);
+        reportError12(ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter, []);
       }
       //
       // Handle the end of parameter groups.
@@ -2111,11 +2110,11 @@
         currentParameters = normalParameters;
         if (leftSquareBracket == null) {
           if (leftCurlyBracket != null) {
-            reportError12(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
+            reportError13(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
             rightCurlyBracket = rightSquareBracket;
             rightSquareBracket = null;
           } else {
-            reportError12(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["["]);
+            reportError13(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["["]);
           }
         }
         kind = ParameterKind.REQUIRED;
@@ -2124,11 +2123,11 @@
         currentParameters = normalParameters;
         if (leftCurlyBracket == null) {
           if (leftSquareBracket != null) {
-            reportError12(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
+            reportError13(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
             rightSquareBracket = rightCurlyBracket;
             rightCurlyBracket = null;
           } else {
-            reportError12(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["{"]);
+            reportError13(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["{"]);
           }
         }
         kind = ParameterKind.REQUIRED;
@@ -2139,10 +2138,10 @@
     // Check that the groups were closed correctly.
     //
     if (leftSquareBracket != null && rightSquareBracket == null) {
-      reportError12(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
+      reportError13(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
     }
     if (leftCurlyBracket != null && rightCurlyBracket == null) {
-      reportError12(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
+      reportError13(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
     }
     //
     // Build the parameter list.
@@ -2259,9 +2258,9 @@
    * @return the map literal entry that was parsed
    */
   MapLiteralEntry parseMapLiteralEntry() {
-    Expression key = parseExpression4();
+    Expression key = parseExpression2();
     Token separator = expect2(TokenType.COLON);
-    Expression value = parseExpression4();
+    Expression value = parseExpression2();
     return new MapLiteralEntry(key, separator, value);
   }
 
@@ -2301,7 +2300,7 @@
       FormalParameterList parameters = parseFormalParameterList();
       if (thisKeyword == null) {
         if (holder.keyword != null) {
-          reportError13(ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword, []);
+          reportError14(ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword, []);
         }
         return new FunctionTypedFormalParameter(commentAndMetadata.comment, commentAndMetadata.metadata, holder.type, identifier, parameters);
       } else {
@@ -2311,9 +2310,9 @@
     TypeName type = holder.type;
     if (type != null) {
       if (matches3(type.name.beginToken, Keyword.VOID)) {
-        reportError13(ParserErrorCode.VOID_PARAMETER, type.name.beginToken, []);
+        reportError14(ParserErrorCode.VOID_PARAMETER, type.name.beginToken, []);
       } else if (holder.keyword != null && matches3(holder.keyword, Keyword.VAR)) {
-        reportError13(ParserErrorCode.VAR_AND_TYPE, holder.keyword, []);
+        reportError14(ParserErrorCode.VAR_AND_TYPE, holder.keyword, []);
       }
     }
     if (thisKeyword != null) {
@@ -2375,7 +2374,7 @@
     if (matchesIdentifier()) {
       return new SimpleIdentifier(andAdvance);
     }
-    reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+    reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
     return createSyntheticIdentifier();
   }
 
@@ -2423,7 +2422,7 @@
       }
     }
     if (strings.length < 1) {
-      reportError12(ParserErrorCode.EXPECTED_STRING_LITERAL, []);
+      reportError13(ParserErrorCode.EXPECTED_STRING_LITERAL, []);
       return createSyntheticStringLiteral();
     } else if (strings.length == 1) {
       return strings[0];
@@ -2469,13 +2468,13 @@
   TypeName parseTypeName() {
     Identifier typeName;
     if (matches(Keyword.VAR)) {
-      reportError12(ParserErrorCode.VAR_AS_TYPE_NAME, []);
+      reportError13(ParserErrorCode.VAR_AS_TYPE_NAME, []);
       typeName = new SimpleIdentifier(andAdvance);
     } else if (matchesIdentifier()) {
       typeName = parsePrefixedIdentifier();
     } else {
       typeName = createSyntheticIdentifier();
-      reportError12(ParserErrorCode.EXPECTED_TYPE_NAME, []);
+      reportError13(ParserErrorCode.EXPECTED_TYPE_NAME, []);
     }
     TypeArgumentList typeArguments = null;
     if (matches5(TokenType.LT)) {
@@ -2570,7 +2569,7 @@
    */
   void appendScalarValue(JavaStringBuilder builder, String escapeSequence, int scalarValue, int startIndex, int endIndex) {
     if (scalarValue < 0 || scalarValue > Character.MAX_CODE_POINT || (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) {
-      reportError12(ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
+      reportError13(ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
       return;
     }
     if (scalarValue < Character.MAX_VALUE) {
@@ -2730,7 +2729,7 @@
    */
   void ensureAssignable(Expression expression) {
     if (expression != null && !expression.isAssignable) {
-      reportError12(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, []);
+      reportError13(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, []);
     }
   }
 
@@ -2747,7 +2746,7 @@
     }
     // Remove uses of this method in favor of matches?
     // Pass in the error code to use to report the error?
-    reportError12(ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
+    reportError13(ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
     return _currentToken;
   }
 
@@ -2765,9 +2764,9 @@
     // Remove uses of this method in favor of matches?
     // Pass in the error code to use to report the error?
     if (identical(type, TokenType.SEMICOLON)) {
-      reportError13(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [type.lexeme]);
+      reportError14(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [type.lexeme]);
     } else {
-      reportError12(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
+      reportError13(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
     }
     return _currentToken;
   }
@@ -3308,7 +3307,7 @@
   ArgumentDefinitionTest parseArgumentDefinitionTest() {
     Token question = expect2(TokenType.QUESTION);
     SimpleIdentifier identifier = parseSimpleIdentifier();
-    reportError13(ParserErrorCode.DEPRECATED_ARGUMENT_DEFINITION_TEST, question, []);
+    reportError14(ParserErrorCode.DEPRECATED_ARGUMENT_DEFINITION_TEST, question, []);
     return new ArgumentDefinitionTest(question, identifier);
   }
 
@@ -3325,15 +3324,15 @@
   AssertStatement parseAssertStatement() {
     Token keyword = expect(Keyword.ASSERT);
     Token leftParen = expect2(TokenType.OPEN_PAREN);
-    Expression expression = parseExpression4();
+    Expression expression = parseExpression2();
     if (expression is AssignmentExpression) {
-      reportError11(ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression, []);
+      reportError12(ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression, []);
     } else if (expression is CascadeExpression) {
-      reportError11(ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression, []);
+      reportError12(ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression, []);
     } else if (expression is ThrowExpression) {
-      reportError11(ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression, []);
+      reportError12(ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression, []);
     } else if (expression is RethrowExpression) {
-      reportError11(ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression, []);
+      reportError12(ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression, []);
     }
     Token rightParen = expect2(TokenType.CLOSE_PAREN);
     Token semicolon = expect2(TokenType.SEMICOLON);
@@ -3412,7 +3411,7 @@
   Expression parseAssignableSelector(Expression prefix, bool optional) {
     if (matches5(TokenType.OPEN_SQUARE_BRACKET)) {
       Token leftBracket = andAdvance;
-      Expression index = parseExpression4();
+      Expression index = parseExpression2();
       Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET);
       return new IndexExpression.forTarget(prefix, leftBracket, index, rightBracket);
     } else if (matches5(TokenType.PERIOD)) {
@@ -3421,7 +3420,7 @@
     } else {
       if (!optional) {
         // Report the missing selector.
-        reportError12(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
+        reportError13(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
       }
       return prefix;
     }
@@ -3494,7 +3493,7 @@
       label = parseSimpleIdentifier();
     }
     if (!_inLoop && !_inSwitch && label == null) {
-      reportError13(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword, []);
+      reportError14(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword, []);
     }
     Token semicolon = expect2(TokenType.SEMICOLON);
     return new BreakStatement(breakKeyword, label, semicolon);
@@ -3525,12 +3524,12 @@
       functionName = parseSimpleIdentifier();
     } else if (identical(_currentToken.type, TokenType.OPEN_SQUARE_BRACKET)) {
       Token leftBracket = andAdvance;
-      Expression index = parseExpression4();
+      Expression index = parseExpression2();
       Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET);
       expression = new IndexExpression.forCascade(period, leftBracket, index, rightBracket);
       period = null;
     } else {
-      reportError13(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, [_currentToken.lexeme]);
+      reportError14(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, [_currentToken.lexeme]);
       functionName = createSyntheticIdentifier();
     }
     if (identical(_currentToken.type, TokenType.OPEN_PAREN)) {
@@ -3621,29 +3620,29 @@
         if (extendsClause == null) {
           extendsClause = parseExtendsClause();
           if (withClause != null) {
-            reportError13(ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword, []);
+            reportError14(ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword, []);
           } else if (implementsClause != null) {
-            reportError13(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, implementsClause.keyword, []);
+            reportError14(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, implementsClause.keyword, []);
           }
         } else {
-          reportError13(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, extendsClause.keyword, []);
+          reportError14(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, extendsClause.keyword, []);
           parseExtendsClause();
         }
       } else if (matches(Keyword.WITH)) {
         if (withClause == null) {
           withClause = parseWithClause();
           if (implementsClause != null) {
-            reportError13(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, implementsClause.keyword, []);
+            reportError14(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, implementsClause.keyword, []);
           }
         } else {
-          reportError13(ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword, []);
+          reportError14(ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword, []);
           parseWithClause();
         }
       } else if (matches(Keyword.IMPLEMENTS)) {
         if (implementsClause == null) {
           implementsClause = parseImplementsClause();
         } else {
-          reportError13(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, implementsClause.keyword, []);
+          reportError14(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, implementsClause.keyword, []);
           parseImplementsClause();
         }
       } else {
@@ -3651,7 +3650,7 @@
       }
     }
     if (withClause != null && extendsClause == null) {
-      reportError13(ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword, []);
+      reportError14(ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword, []);
     }
     //
     // Look for and skip over the extra-lingual 'native' specification.
@@ -3673,7 +3672,7 @@
     } else {
       leftBracket = createSyntheticToken2(TokenType.OPEN_CURLY_BRACKET);
       rightBracket = createSyntheticToken2(TokenType.CLOSE_CURLY_BRACKET);
-      reportError12(ParserErrorCode.MISSING_CLASS_BODY, []);
+      reportError13(ParserErrorCode.MISSING_CLASS_BODY, []);
     }
     ClassDeclaration classDeclaration = new ClassDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, abstractKeyword, keyword, name, typeParameters, extendsClause, withClause, implementsClause, leftBracket, members, rightBracket);
     classDeclaration.nativeClause = nativeClause;
@@ -3698,7 +3697,7 @@
     Token memberStart = _currentToken;
     while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET) && (closingBracket != null || (!matches(Keyword.CLASS) && !matches(Keyword.TYPEDEF)))) {
       if (matches5(TokenType.SEMICOLON)) {
-        reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+        reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
         advance();
       } else {
         ClassMember member = parseClassMember(className);
@@ -3707,7 +3706,7 @@
         }
       }
       if (identical(_currentToken, memberStart)) {
-        reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+        reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
         advance();
       }
       memberStart = _currentToken;
@@ -3755,12 +3754,12 @@
       semicolon = andAdvance;
     } else {
       if (matches5(TokenType.OPEN_CURLY_BRACKET)) {
-        reportError12(ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
+        reportError13(ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
         Token leftBracket = andAdvance;
         parseClassMembers(className.name, getEndToken(leftBracket));
         expect2(TokenType.CLOSE_CURLY_BRACKET);
       } else {
-        reportError13(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
+        reportError14(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
       }
       semicolon = createSyntheticToken2(TokenType.SEMICOLON);
     }
@@ -3838,7 +3837,7 @@
     }
     try {
       BooleanErrorListener listener = new BooleanErrorListener();
-      Scanner scanner = new Scanner(null, new SubSequenceReader(new CharSequence(referenceSource), sourceOffset), listener);
+      Scanner scanner = new Scanner(null, new SubSequenceReader(referenceSource, sourceOffset), listener);
       scanner.setSourceStart(1, 1);
       Token firstToken = scanner.tokenize();
       if (listener.errorReported) {
@@ -3959,7 +3958,7 @@
         validateModifiersForTopLevelFunction(modifiers);
         return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, returnType);
       } else if (matches(Keyword.OPERATOR) && isOperator(peek())) {
-        reportError13(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
+        reportError14(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
         return convertToFunctionDeclaration(parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType));
       } else if (matchesIdentifier() && matchesAny(peek(), [
           TokenType.OPEN_PAREN,
@@ -3976,28 +3975,28 @@
             //
             // We appear to have a variable declaration with a type of "void".
             //
-            reportError11(ParserErrorCode.VOID_VARIABLE, returnType, []);
+            reportError12(ParserErrorCode.VOID_VARIABLE, returnType, []);
             return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiersForTopLevelVariable(modifiers), null), expect2(TokenType.SEMICOLON));
           }
         }
-        reportError13(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
+        reportError14(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
         return null;
       }
     } else if ((matches(Keyword.GET) || matches(Keyword.SET)) && matchesIdentifier2(peek())) {
       validateModifiersForTopLevelFunction(modifiers);
       return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, null);
     } else if (matches(Keyword.OPERATOR) && isOperator(peek())) {
-      reportError13(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
+      reportError14(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
       return convertToFunctionDeclaration(parseOperator(commentAndMetadata, modifiers.externalKeyword, null));
     } else if (!matchesIdentifier()) {
-      reportError13(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
+      reportError14(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
       return null;
     } else if (matches4(peek(), TokenType.OPEN_PAREN)) {
       validateModifiersForTopLevelFunction(modifiers);
       return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, null);
     } else if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
       if (modifiers.constKeyword == null && modifiers.finalKeyword == null && modifiers.varKeyword == null) {
-        reportError12(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
+        reportError13(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
       }
       return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiersForTopLevelVariable(modifiers), null), expect2(TokenType.SEMICOLON));
     }
@@ -4006,13 +4005,13 @@
       validateModifiersForTopLevelFunction(modifiers);
       return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, returnType);
     } else if (matches(Keyword.OPERATOR) && isOperator(peek())) {
-      reportError13(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
+      reportError14(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
       return convertToFunctionDeclaration(parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType));
     } else if (matches5(TokenType.AT)) {
       return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiersForTopLevelVariable(modifiers), returnType), expect2(TokenType.SEMICOLON));
     } else if (!matchesIdentifier()) {
       // TODO(brianwilkerson) Generalize this error. We could also be parsing a top-level variable at this point.
-      reportError13(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
+      reportError14(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
       Token semicolon;
       if (matches5(TokenType.SEMICOLON)) {
         semicolon = andAdvance;
@@ -4089,21 +4088,21 @@
       redirectedConstructor = parseConstructorName();
       body = new EmptyFunctionBody(expect2(TokenType.SEMICOLON));
       if (factoryKeyword == null) {
-        reportError11(ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, redirectedConstructor, []);
+        reportError12(ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, redirectedConstructor, []);
       }
     } else {
       body = parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
       if (constKeyword != null && factoryKeyword != null && externalKeyword == null) {
-        reportError13(ParserErrorCode.CONST_FACTORY, factoryKeyword, []);
+        reportError14(ParserErrorCode.CONST_FACTORY, factoryKeyword, []);
       } else if (body is EmptyFunctionBody) {
         if (factoryKeyword != null && externalKeyword == null) {
-          reportError13(ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword, []);
+          reportError14(ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword, []);
         }
       } else {
         if (constKeyword != null) {
-          reportError11(ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body, []);
+          reportError12(ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body, []);
         } else if (!bodyAllowed) {
-          reportError11(ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body, []);
+          reportError12(ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body, []);
         }
       }
     }
@@ -4158,14 +4157,14 @@
   Statement parseContinueStatement() {
     Token continueKeyword = expect(Keyword.CONTINUE);
     if (!_inLoop && !_inSwitch) {
-      reportError13(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword, []);
+      reportError14(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword, []);
     }
     SimpleIdentifier label = null;
     if (matchesIdentifier()) {
       label = parseSimpleIdentifier();
     }
     if (_inSwitch && !_inLoop && label == null) {
-      reportError13(ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword, []);
+      reportError14(ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword, []);
     }
     Token semicolon = expect2(TokenType.SEMICOLON);
     return new ContinueStatement(continueKeyword, label, semicolon);
@@ -4257,7 +4256,7 @@
       Statement body = parseStatement2();
       Token whileKeyword = expect(Keyword.WHILE);
       Token leftParenthesis = expect2(TokenType.OPEN_PAREN);
-      Expression condition = parseExpression4();
+      Expression condition = parseExpression2();
       Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
       Token semicolon = expect2(TokenType.SEMICOLON);
       return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, condition, rightParenthesis, semicolon);
@@ -4300,7 +4299,7 @@
     while (_currentToken.type.isEqualityOperator) {
       Token operator = andAdvance;
       if (leftEqualityExpression) {
-        reportError11(ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression, []);
+        reportError12(ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression, []);
       }
       expression = new BinaryExpression(expression, operator, parseRelationalExpression());
       leftEqualityExpression = true;
@@ -4339,9 +4338,9 @@
    */
   List<Expression> parseExpressionList() {
     List<Expression> expressions = new List<Expression>();
-    expressions.add(parseExpression4());
+    expressions.add(parseExpression2());
     while (optional(TokenType.COMMA)) {
-      expressions.add(parseExpression4());
+      expressions.add(parseExpression2());
     }
     return expressions;
   }
@@ -4374,7 +4373,7 @@
       if (isTypedIdentifier(_currentToken)) {
         type = parseReturnType();
       } else if (!optional) {
-        reportError12(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
+        reportError13(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
       }
     }
     return new FinalConstVarOrType(keyword, type);
@@ -4400,20 +4399,20 @@
     NormalFormalParameter parameter = parseNormalFormalParameter();
     if (matches5(TokenType.EQ)) {
       Token seperator = andAdvance;
-      Expression defaultValue = parseExpression4();
+      Expression defaultValue = parseExpression2();
       if (identical(kind, ParameterKind.NAMED)) {
-        reportError13(ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator, []);
+        reportError14(ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator, []);
       } else if (identical(kind, ParameterKind.REQUIRED)) {
-        reportError11(ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter, []);
+        reportError12(ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter, []);
       }
       return new DefaultFormalParameter(parameter, kind, seperator, defaultValue);
     } else if (matches5(TokenType.COLON)) {
       Token seperator = andAdvance;
-      Expression defaultValue = parseExpression4();
+      Expression defaultValue = parseExpression2();
       if (identical(kind, ParameterKind.POSITIONAL)) {
-        reportError13(ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, seperator, []);
+        reportError14(ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, seperator, []);
       } else if (identical(kind, ParameterKind.REQUIRED)) {
-        reportError11(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter, []);
+        reportError12(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter, []);
       }
       return new DefaultFormalParameter(parameter, kind, seperator, defaultValue);
     } else if (kind != ParameterKind.REQUIRED) {
@@ -4459,22 +4458,22 @@
         } else if (isInitializedVariableDeclaration()) {
           variableList = parseVariableDeclarationList(commentAndMetadata);
         } else {
-          initialization = parseExpression4();
+          initialization = parseExpression2();
         }
         if (matches(Keyword.IN)) {
           DeclaredIdentifier loopVariable = null;
           SimpleIdentifier identifier = null;
           if (variableList == null) {
             // We found: <expression> 'in'
-            reportError12(ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH, []);
+            reportError13(ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH, []);
           } else {
             NodeList<VariableDeclaration> variables = variableList.variables;
             if (variables.length > 1) {
-              reportError12(ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, [variables.length.toString()]);
+              reportError13(ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, [variables.length.toString()]);
             }
             VariableDeclaration variable = variables[0];
             if (variable.initializer != null) {
-              reportError12(ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH, []);
+              reportError13(ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH, []);
             }
             Token keyword = variableList.keyword;
             TypeName type = variableList.type;
@@ -4487,7 +4486,7 @@
             }
           }
           Token inKeyword = expect(Keyword.IN);
-          Expression iterator = parseExpression4();
+          Expression iterator = parseExpression2();
           Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
           Statement body = parseStatement2();
           if (loopVariable == null) {
@@ -4499,7 +4498,7 @@
       Token leftSeparator = expect2(TokenType.SEMICOLON);
       Expression condition = null;
       if (!matches5(TokenType.SEMICOLON)) {
-        condition = parseExpression4();
+        condition = parseExpression2();
       }
       Token rightSeparator = expect2(TokenType.SEMICOLON);
       List<Expression> updaters = null;
@@ -4541,12 +4540,12 @@
     try {
       if (matches5(TokenType.SEMICOLON)) {
         if (!mayBeEmpty) {
-          reportError12(emptyErrorCode, []);
+          reportError13(emptyErrorCode, []);
         }
         return new EmptyFunctionBody(andAdvance);
       } else if (matches5(TokenType.FUNCTION)) {
         Token functionDefinition = andAdvance;
-        Expression expression = parseExpression4();
+        Expression expression = parseExpression2();
         Token semicolon = null;
         if (!inExpression) {
           semicolon = expect2(TokenType.SEMICOLON);
@@ -4570,7 +4569,7 @@
         return new NativeFunctionBody(nativeToken, stringLiteral, expect2(TokenType.SEMICOLON));
       } else {
         // Invalid function body
-        reportError12(emptyErrorCode, []);
+        reportError13(emptyErrorCode, []);
         return new EmptyFunctionBody(createSyntheticToken2(TokenType.SEMICOLON));
       }
     } finally {
@@ -4611,10 +4610,10 @@
         parameters = parseFormalParameterList();
         validateFormalParameterList(parameters);
       } else {
-        reportError12(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, []);
+        reportError13(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, []);
       }
     } else if (matches5(TokenType.OPEN_PAREN)) {
-      reportError12(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
+      reportError13(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
       parseFormalParameterList();
     }
     FunctionBody body;
@@ -4665,9 +4664,9 @@
     Token propertyKeyword = declaration.propertyKeyword;
     if (propertyKeyword != null) {
       if (identical((propertyKeyword as KeywordToken).keyword, Keyword.GET)) {
-        reportError13(ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword, []);
+        reportError14(ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword, []);
       } else {
-        reportError13(ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword, []);
+        reportError14(ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword, []);
       }
     }
     return new FunctionDeclarationStatement(declaration);
@@ -4699,12 +4698,12 @@
       typeParameters = parseTypeParameterList();
     }
     if (matches5(TokenType.SEMICOLON) || matches5(TokenType.EOF)) {
-      reportError12(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
+      reportError13(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
       FormalParameterList parameters = new FormalParameterList(createSyntheticToken2(TokenType.OPEN_PAREN), null, null, null, createSyntheticToken2(TokenType.CLOSE_PAREN));
       Token semicolon = expect2(TokenType.SEMICOLON);
       return new FunctionTypeAlias(commentAndMetadata.comment, commentAndMetadata.metadata, keyword, returnType, name, typeParameters, parameters, semicolon);
     } else if (!matches5(TokenType.OPEN_PAREN)) {
-      reportError12(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
+      reportError13(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
       // TODO(brianwilkerson) Recover from this error. At the very least we should skip to the start
       // of the next valid compilation unit member, allowing for the possibility of finding the
       // typedef parameters before that point.
@@ -4739,13 +4738,13 @@
     Token propertyKeyword = expect(Keyword.GET);
     SimpleIdentifier name = parseSimpleIdentifier();
     if (matches5(TokenType.OPEN_PAREN) && matches4(peek(), TokenType.CLOSE_PAREN)) {
-      reportError12(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
+      reportError13(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
       advance();
       advance();
     }
     FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, false);
     if (externalKeyword != null && body is! EmptyFunctionBody) {
-      reportError12(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY, []);
+      reportError13(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY, []);
     }
     return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null, name, null, body);
   }
@@ -4783,7 +4782,7 @@
   Statement parseIfStatement() {
     Token ifKeyword = expect(Keyword.IF);
     Token leftParenthesis = expect2(TokenType.OPEN_PAREN);
-    Expression condition = parseExpression4();
+    Expression condition = parseExpression2();
     Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
     Statement thenStatement = parseStatement2();
     Token elseKeyword = null;
@@ -4903,9 +4902,9 @@
       // TODO(brianwilkerson) Recovery: This should be extended to handle arbitrary tokens until we
       // can find a token that can start a compilation unit member.
       StringLiteral string = parseStringLiteral();
-      reportError11(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string, []);
+      reportError12(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string, []);
     } else {
-      reportError13(missingNameError, missingNameToken, []);
+      reportError14(missingNameError, missingNameToken, []);
     }
     List<SimpleIdentifier> components = new List<SimpleIdentifier>();
     components.add(createSyntheticIdentifier());
@@ -4944,12 +4943,12 @@
       return new ListLiteral(modifier, typeArguments, leftBracket, null, andAdvance);
     }
     List<Expression> elements = new List<Expression>();
-    elements.add(parseExpression4());
+    elements.add(parseExpression2());
     while (optional(TokenType.COMMA)) {
       if (matches5(TokenType.CLOSE_SQUARE_BRACKET)) {
         return new ListLiteral(modifier, typeArguments, leftBracket, elements, andAdvance);
       }
-      elements.add(parseExpression4());
+      elements.add(parseExpression2());
     }
     Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET);
     return new ListLiteral(modifier, typeArguments, leftBracket, elements, rightBracket);
@@ -4978,7 +4977,7 @@
     } else if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.INDEX)) {
       return parseListLiteral(modifier, typeArguments);
     }
-    reportError12(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL, []);
+    reportError13(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL, []);
     return new ListLiteral(modifier, typeArguments, createSyntheticToken2(TokenType.OPEN_SQUARE_BRACKET), null, createSyntheticToken2(TokenType.CLOSE_SQUARE_BRACKET));
   }
 
@@ -5077,11 +5076,11 @@
     FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.MISSING_FUNCTION_BODY, false);
     if (externalKeyword != null) {
       if (body is! EmptyFunctionBody) {
-        reportError11(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body, []);
+        reportError12(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body, []);
       }
     } else if (staticKeyword != null) {
       if (body is EmptyFunctionBody) {
-        reportError11(ParserErrorCode.ABSTRACT_STATIC_METHOD, body, []);
+        reportError12(ParserErrorCode.ABSTRACT_STATIC_METHOD, body, []);
       }
     }
     return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, null, null, name, parameters, body);
@@ -5109,49 +5108,49 @@
       }
       if (matches(Keyword.ABSTRACT)) {
         if (modifiers.abstractKeyword != null) {
-          reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+          reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
           advance();
         } else {
           modifiers.abstractKeyword = andAdvance;
         }
       } else if (matches(Keyword.CONST)) {
         if (modifiers.constKeyword != null) {
-          reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+          reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
           advance();
         } else {
           modifiers.constKeyword = andAdvance;
         }
       } else if (matches(Keyword.EXTERNAL) && !matches4(peek(), TokenType.PERIOD) && !matches4(peek(), TokenType.LT)) {
         if (modifiers.externalKeyword != null) {
-          reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+          reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
           advance();
         } else {
           modifiers.externalKeyword = andAdvance;
         }
       } else if (matches(Keyword.FACTORY) && !matches4(peek(), TokenType.PERIOD) && !matches4(peek(), TokenType.LT)) {
         if (modifiers.factoryKeyword != null) {
-          reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+          reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
           advance();
         } else {
           modifiers.factoryKeyword = andAdvance;
         }
       } else if (matches(Keyword.FINAL)) {
         if (modifiers.finalKeyword != null) {
-          reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+          reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
           advance();
         } else {
           modifiers.finalKeyword = andAdvance;
         }
       } else if (matches(Keyword.STATIC) && !matches4(peek(), TokenType.PERIOD) && !matches4(peek(), TokenType.LT)) {
         if (modifiers.staticKeyword != null) {
-          reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+          reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
           advance();
         } else {
           modifiers.staticKeyword = andAdvance;
         }
       } else if (matches(Keyword.VAR)) {
         if (modifiers.varKeyword != null) {
-          reportError12(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
+          reportError13(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
           advance();
         } else {
           modifiers.varKeyword = andAdvance;
@@ -5246,7 +5245,7 @@
       if (matches4(peek(), TokenType.STRING)) {
         Token afterString = skipStringLiteral(_currentToken.next);
         if (afterString != null && identical(afterString.type, TokenType.COLON)) {
-          return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+          return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
         }
       }
       return parseBlock();
@@ -5295,7 +5294,7 @@
               //
               // We appear to have a variable declaration with a type of "void".
               //
-              reportError11(ParserErrorCode.VOID_VARIABLE, returnType, []);
+              reportError12(ParserErrorCode.VOID_VARIABLE, returnType, []);
               return parseVariableDeclarationStatement(commentAndMetadata);
             }
           } else if (matches5(TokenType.CLOSE_CURLY_BRACKET)) {
@@ -5305,7 +5304,7 @@
             //
             return parseVariableDeclarationStatement2(commentAndMetadata, null, returnType);
           }
-          reportError12(ParserErrorCode.MISSING_STATEMENT, []);
+          reportError13(ParserErrorCode.MISSING_STATEMENT, []);
           // TODO(brianwilkerson) Recover from this error.
           return new EmptyStatement(createSyntheticToken2(TokenType.SEMICOLON));
         }
@@ -5315,23 +5314,23 @@
             TokenType.OPEN_CURLY_BRACKET,
             TokenType.OPEN_SQUARE_BRACKET,
             TokenType.INDEX])) {
-          return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+          return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
         } else if (matches4(peek(), TokenType.IDENTIFIER)) {
           Token afterType = skipTypeName(peek());
           if (afterType != null) {
             if (matches4(afterType, TokenType.OPEN_PAREN) || (matches4(afterType, TokenType.PERIOD) && matches4(afterType.next, TokenType.IDENTIFIER) && matches4(afterType.next.next, TokenType.OPEN_PAREN))) {
-              return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+              return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
             }
           }
         }
         return parseVariableDeclarationStatement(commentAndMetadata);
       } else if (identical(keyword, Keyword.NEW) || identical(keyword, Keyword.TRUE) || identical(keyword, Keyword.FALSE) || identical(keyword, Keyword.NULL) || identical(keyword, Keyword.SUPER) || identical(keyword, Keyword.THIS)) {
-        return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+        return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
       } else {
         //
         // We have found an error of some kind. Try to recover.
         //
-        reportError12(ParserErrorCode.MISSING_STATEMENT, []);
+        reportError13(ParserErrorCode.MISSING_STATEMENT, []);
         return new EmptyStatement(createSyntheticToken2(TokenType.SEMICOLON));
       }
     } else if (matches5(TokenType.SEMICOLON)) {
@@ -5341,10 +5340,10 @@
     } else if (isFunctionDeclaration()) {
       return parseFunctionDeclarationStatement();
     } else if (matches5(TokenType.CLOSE_CURLY_BRACKET)) {
-      reportError12(ParserErrorCode.MISSING_STATEMENT, []);
+      reportError13(ParserErrorCode.MISSING_STATEMENT, []);
       return new EmptyStatement(createSyntheticToken2(TokenType.SEMICOLON));
     } else {
-      return new ExpressionStatement(parseExpression4(), expect2(TokenType.SEMICOLON));
+      return new ExpressionStatement(parseExpression2(), expect2(TokenType.SEMICOLON));
     }
   }
 
@@ -5371,17 +5370,17 @@
     if (matches(Keyword.OPERATOR)) {
       operatorKeyword = andAdvance;
     } else {
-      reportError13(ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken, []);
+      reportError14(ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken, []);
       operatorKeyword = createSyntheticToken(Keyword.OPERATOR);
     }
     if (!_currentToken.isUserDefinableOperator) {
-      reportError12(ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]);
+      reportError13(ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]);
     }
     SimpleIdentifier name = new SimpleIdentifier(andAdvance);
     if (matches5(TokenType.EQ)) {
       Token previous = _currentToken.previous;
       if ((matches4(previous, TokenType.EQ_EQ) || matches4(previous, TokenType.BANG_EQ)) && _currentToken.offset == previous.offset + 2) {
-        reportError12(ParserErrorCode.INVALID_OPERATOR, ["${previous.lexeme}${_currentToken.lexeme}"]);
+        reportError13(ParserErrorCode.INVALID_OPERATOR, ["${previous.lexeme}${_currentToken.lexeme}"]);
         advance();
       }
     }
@@ -5389,7 +5388,7 @@
     validateFormalParameterList(parameters);
     FunctionBody body = parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
     if (externalKeyword != null && body is! EmptyFunctionBody) {
-      reportError12(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY, []);
+      reportError13(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY, []);
     }
     return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, null, returnType, null, operatorKeyword, name, parameters, body);
   }
@@ -5474,7 +5473,7 @@
       return operand;
     }
     if (operand is Literal || operand is FunctionExpressionInvocation) {
-      reportError12(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
+      reportError13(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
     }
     Token operator = andAdvance;
     return new PostfixExpression(operand, operator);
@@ -5569,7 +5568,7 @@
         return parseFunctionExpression();
       }
       Token leftParenthesis = andAdvance;
-      Expression expression = parseExpression4();
+      Expression expression = parseExpression2();
       Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
       return new ParenthesizedExpression(leftParenthesis, expression, rightParenthesis);
     } else if (matches5(TokenType.LT)) {
@@ -5581,13 +5580,13 @@
       // Recover from having a return type of "void" where a return type is not expected.
       //
       // TODO(brianwilkerson) Improve this error message.
-      reportError12(ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
+      reportError13(ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
       advance();
       return parsePrimaryExpression();
     } else if (matches5(TokenType.HASH)) {
       return parseSymbolLiteral();
     } else {
-      reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+      reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
       return createSyntheticIdentifier();
     }
   }
@@ -5677,7 +5676,7 @@
     if (matches5(TokenType.SEMICOLON)) {
       return new ReturnStatement(returnKeyword, null, andAdvance);
     }
-    Expression expression = parseExpression4();
+    Expression expression = parseExpression2();
     Token semicolon = expect2(TokenType.SEMICOLON);
     return new ReturnStatement(returnKeyword, expression, semicolon);
   }
@@ -5708,7 +5707,7 @@
     validateFormalParameterList(parameters);
     FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, false);
     if (externalKeyword != null && body is! EmptyFunctionBody) {
-      reportError12(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY, []);
+      reportError13(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY, []);
     }
     return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null, name, parameters, body);
   }
@@ -5754,7 +5753,7 @@
     while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET) && !isSwitchMember()) {
       statements.add(parseStatement2());
       if (identical(_currentToken, statementStart)) {
-        reportError13(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
+        reportError14(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
         advance();
       }
       statementStart = _currentToken;
@@ -5774,7 +5773,7 @@
     while (hasMore) {
       if (matches5(TokenType.STRING_INTERPOLATION_EXPRESSION)) {
         Token openToken = andAdvance;
-        Expression expression = parseExpression4();
+        Expression expression = parseExpression2();
         Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET);
         elements.add(new InterpolationExpression(openToken, expression, rightBracket));
       } else {
@@ -5841,7 +5840,7 @@
       Set<String> definedLabels = new Set<String>();
       Token keyword = expect(Keyword.SWITCH);
       Token leftParenthesis = expect2(TokenType.OPEN_PAREN);
-      Expression expression = parseExpression4();
+      Expression expression = parseExpression2();
       Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
       Token leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET);
       Token defaultKeyword = null;
@@ -5852,7 +5851,7 @@
           SimpleIdentifier identifier = parseSimpleIdentifier();
           String label = identifier.token.lexeme;
           if (definedLabels.contains(label)) {
-            reportError13(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, identifier.token, [label]);
+            reportError14(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, identifier.token, [label]);
           } else {
             definedLabels.add(label);
           }
@@ -5861,15 +5860,15 @@
         }
         if (matches(Keyword.CASE)) {
           Token caseKeyword = andAdvance;
-          Expression caseExpression = parseExpression4();
+          Expression caseExpression = parseExpression2();
           Token colon = expect2(TokenType.COLON);
           members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon, parseStatements2()));
           if (defaultKeyword != null) {
-            reportError13(ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, caseKeyword, []);
+            reportError14(ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, caseKeyword, []);
           }
         } else if (matches(Keyword.DEFAULT)) {
           if (defaultKeyword != null) {
-            reportError13(ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, peek(), []);
+            reportError14(ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, peek(), []);
           }
           defaultKeyword = andAdvance;
           Token colon = expect2(TokenType.COLON);
@@ -5877,7 +5876,7 @@
         } else {
           // We need to advance, otherwise we could end up in an infinite loop, but this could be a
           // lot smarter about recovering from the error.
-          reportError12(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, []);
+          reportError13(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, []);
           while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET) && !matches(Keyword.CASE) && !matches(Keyword.DEFAULT)) {
             advance();
           }
@@ -5910,7 +5909,7 @@
         if (matchesIdentifier()) {
           components.add(andAdvance);
         } else {
-          reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+          reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
           components.add(createSyntheticToken2(TokenType.IDENTIFIER));
           break;
         }
@@ -5918,7 +5917,7 @@
     } else if (_currentToken.isOperator) {
       components.add(andAdvance);
     } else {
-      reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+      reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
       components.add(createSyntheticToken2(TokenType.IDENTIFIER));
     }
     return new SymbolLiteral(poundSign, new List.from(components));
@@ -5937,10 +5936,10 @@
   Expression parseThrowExpression() {
     Token keyword = expect(Keyword.THROW);
     if (matches5(TokenType.SEMICOLON) || matches5(TokenType.CLOSE_PAREN)) {
-      reportError13(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
+      reportError14(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
       return new ThrowExpression(keyword, createSyntheticIdentifier());
     }
-    Expression expression = parseExpression4();
+    Expression expression = parseExpression2();
     return new ThrowExpression(keyword, expression);
   }
 
@@ -5957,7 +5956,7 @@
   Expression parseThrowExpressionWithoutCascade() {
     Token keyword = expect(Keyword.THROW);
     if (matches5(TokenType.SEMICOLON) || matches5(TokenType.CLOSE_PAREN)) {
-      reportError13(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
+      reportError14(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
       return new ThrowExpression(keyword, createSyntheticIdentifier());
     }
     Expression expression = parseExpressionWithoutCascade();
@@ -6021,7 +6020,7 @@
       finallyClause = parseBlock();
     } else {
       if (catchClauses.isEmpty) {
-        reportError12(ParserErrorCode.MISSING_CATCH_OR_FINALLY, []);
+        reportError13(ParserErrorCode.MISSING_CATCH_OR_FINALLY, []);
       }
     }
     return new TryStatement(tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
@@ -6062,12 +6061,12 @@
         next = skipTypeParameterList(next);
         if (next != null && matches4(next, TokenType.EQ)) {
           TypeAlias typeAlias = parseClassTypeAlias(commentAndMetadata, null, keyword);
-          reportError13(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
+          reportError14(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
           return typeAlias;
         }
       } else if (matches4(next, TokenType.EQ)) {
         TypeAlias typeAlias = parseClassTypeAlias(commentAndMetadata, null, keyword);
-        reportError13(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
+        reportError14(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
         return typeAlias;
       }
     }
@@ -6124,13 +6123,13 @@
           return new PrefixExpression(firstOperator, new PrefixExpression(secondOperator, new SuperExpression(andAdvance)));
         } else {
           // Invalid operator before 'super'
-          reportError12(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
+          reportError13(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
           return new PrefixExpression(operator, new SuperExpression(andAdvance));
         }
       }
       return new PrefixExpression(operator, parseAssignableExpression(false));
     } else if (matches5(TokenType.PLUS)) {
-      reportError12(ParserErrorCode.MISSING_IDENTIFIER, []);
+      reportError13(ParserErrorCode.MISSING_IDENTIFIER, []);
       return createSyntheticIdentifier();
     }
     return parsePostfixExpression();
@@ -6153,7 +6152,7 @@
     Expression initializer = null;
     if (matches5(TokenType.EQ)) {
       equals = andAdvance;
-      initializer = parseExpression4();
+      initializer = parseExpression2();
     }
     return new VariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, name, equals, initializer);
   }
@@ -6191,7 +6190,7 @@
    */
   VariableDeclarationList parseVariableDeclarationList2(CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
     if (type != null && keyword != null && matches3(keyword, Keyword.VAR)) {
-      reportError13(ParserErrorCode.VAR_AND_TYPE, keyword, []);
+      reportError14(ParserErrorCode.VAR_AND_TYPE, keyword, []);
     }
     List<VariableDeclaration> variables = new List<VariableDeclaration>();
     variables.add(parseVariableDeclaration());
@@ -6264,7 +6263,7 @@
     try {
       Token keyword = expect(Keyword.WHILE);
       Token leftParenthesis = expect2(TokenType.OPEN_PAREN);
-      Expression condition = parseExpression4();
+      Expression condition = parseExpression2();
       Token rightParenthesis = expect2(TokenType.CLOSE_PAREN);
       Statement body = parseStatement2();
       return new WhileStatement(keyword, leftParenthesis, condition, rightParenthesis, body);
@@ -6315,7 +6314,7 @@
    * @param node the node specifying the location of the error
    * @param arguments the arguments to the error, used to compose the error message
    */
-  void reportError11(ParserErrorCode errorCode, ASTNode node, List<Object> arguments) {
+  void reportError12(ParserErrorCode errorCode, ASTNode node, List<Object> arguments) {
     reportError(new AnalysisError.con2(_source, node.offset, node.length, errorCode, arguments));
   }
 
@@ -6325,8 +6324,8 @@
    * @param errorCode the error code of the error to be reported
    * @param arguments the arguments to the error, used to compose the error message
    */
-  void reportError12(ParserErrorCode errorCode, List<Object> arguments) {
-    reportError13(errorCode, _currentToken, arguments);
+  void reportError13(ParserErrorCode errorCode, List<Object> arguments) {
+    reportError14(errorCode, _currentToken, arguments);
   }
 
   /**
@@ -6336,7 +6335,7 @@
    * @param token the token specifying the location of the error
    * @param arguments the arguments to the error, used to compose the error message
    */
-  void reportError13(ParserErrorCode errorCode, Token token, List<Object> arguments) {
+  void reportError14(ParserErrorCode errorCode, Token token, List<Object> arguments) {
     reportError(new AnalysisError.con2(_source, token.offset, token.length, errorCode, arguments));
   }
 
@@ -6817,14 +6816,14 @@
     } else if (currentChar == 0x78) {
       if (currentIndex + 2 >= length) {
         // Illegal escape sequence: not enough hex digits
-        reportError12(ParserErrorCode.INVALID_HEX_ESCAPE, []);
+        reportError13(ParserErrorCode.INVALID_HEX_ESCAPE, []);
         return length;
       }
       int firstDigit = lexeme.codeUnitAt(currentIndex + 1);
       int secondDigit = lexeme.codeUnitAt(currentIndex + 2);
       if (!isHexDigit(firstDigit) || !isHexDigit(secondDigit)) {
         // Illegal escape sequence: invalid hex digit
-        reportError12(ParserErrorCode.INVALID_HEX_ESCAPE, []);
+        reportError13(ParserErrorCode.INVALID_HEX_ESCAPE, []);
       } else {
         builder.appendChar(((Character.digit(firstDigit, 16) << 4) + Character.digit(secondDigit, 16)));
       }
@@ -6833,7 +6832,7 @@
       currentIndex++;
       if (currentIndex >= length) {
         // Illegal escape sequence: not enough hex digits
-        reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+        reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
         return length;
       }
       currentChar = lexeme.codeUnitAt(currentIndex);
@@ -6841,7 +6840,7 @@
         currentIndex++;
         if (currentIndex >= length) {
           // Illegal escape sequence: incomplete escape
-          reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+          reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
           return length;
         }
         currentChar = lexeme.codeUnitAt(currentIndex);
@@ -6850,7 +6849,7 @@
         while (currentChar != 0x7D) {
           if (!isHexDigit(currentChar)) {
             // Illegal escape sequence: invalid hex digit
-            reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+            reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
             currentIndex++;
             while (currentIndex < length && lexeme.codeUnitAt(currentIndex) != 0x7D) {
               currentIndex++;
@@ -6862,21 +6861,21 @@
           currentIndex++;
           if (currentIndex >= length) {
             // Illegal escape sequence: incomplete escape
-            reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+            reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
             return length;
           }
           currentChar = lexeme.codeUnitAt(currentIndex);
         }
         if (digitCount < 1 || digitCount > 6) {
           // Illegal escape sequence: not enough or too many hex digits
-          reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+          reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
         }
         appendScalarValue(builder, lexeme.substring(index, currentIndex + 1), value, index, currentIndex);
         return currentIndex + 1;
       } else {
         if (currentIndex + 3 >= length) {
           // Illegal escape sequence: not enough hex digits
-          reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+          reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
           return length;
         }
         int firstDigit = currentChar;
@@ -6885,7 +6884,7 @@
         int fourthDigit = lexeme.codeUnitAt(currentIndex + 3);
         if (!isHexDigit(firstDigit) || !isHexDigit(secondDigit) || !isHexDigit(thirdDigit) || !isHexDigit(fourthDigit)) {
           // Illegal escape sequence: invalid hex digits
-          reportError12(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
+          reportError13(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
         } else {
           appendScalarValue(builder, lexeme.substring(index, currentIndex + 1), (((((Character.digit(firstDigit, 16) << 4) + Character.digit(secondDigit, 16)) << 4) + Character.digit(thirdDigit, 16)) << 4) + Character.digit(fourthDigit, 16), index, currentIndex + 3);
         }
@@ -6916,7 +6915,7 @@
   void validateFormalParameterList(FormalParameterList parameterList) {
     for (FormalParameter parameter in parameterList.parameters) {
       if (parameter is FieldFormalParameter) {
-        reportError11(ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, parameter.identifier, []);
+        reportError12(ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, parameter.identifier, []);
       }
     }
   }
@@ -6930,16 +6929,16 @@
   Token validateModifiersForClass(Modifiers modifiers) {
     validateModifiersForTopLevelDeclaration(modifiers);
     if (modifiers.constKeyword != null) {
-      reportError13(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
+      reportError14(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
     }
     if (modifiers.externalKeyword != null) {
-      reportError13(ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword, []);
+      reportError14(ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword, []);
     }
     if (modifiers.finalKeyword != null) {
-      reportError13(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
+      reportError14(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
     }
     if (modifiers.varKeyword != null) {
-      reportError13(ParserErrorCode.VAR_CLASS, modifiers.varKeyword, []);
+      reportError14(ParserErrorCode.VAR_CLASS, modifiers.varKeyword, []);
     }
     return modifiers.abstractKeyword;
   }
@@ -6953,25 +6952,25 @@
    */
   Token validateModifiersForConstructor(Modifiers modifiers) {
     if (modifiers.abstractKeyword != null) {
-      reportError12(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
+      reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
     }
     if (modifiers.finalKeyword != null) {
-      reportError13(ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword, []);
+      reportError14(ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword, []);
     }
     if (modifiers.staticKeyword != null) {
-      reportError13(ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword, []);
+      reportError14(ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword, []);
     }
     if (modifiers.varKeyword != null) {
-      reportError13(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKeyword, []);
+      reportError14(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKeyword, []);
     }
     Token externalKeyword = modifiers.externalKeyword;
     Token constKeyword = modifiers.constKeyword;
     Token factoryKeyword = modifiers.factoryKeyword;
     if (externalKeyword != null && constKeyword != null && constKeyword.offset < externalKeyword.offset) {
-      reportError13(ParserErrorCode.EXTERNAL_AFTER_CONST, externalKeyword, []);
+      reportError14(ParserErrorCode.EXTERNAL_AFTER_CONST, externalKeyword, []);
     }
     if (externalKeyword != null && factoryKeyword != null && factoryKeyword.offset < externalKeyword.offset) {
-      reportError13(ParserErrorCode.EXTERNAL_AFTER_FACTORY, externalKeyword, []);
+      reportError14(ParserErrorCode.EXTERNAL_AFTER_FACTORY, externalKeyword, []);
     }
     return constKeyword;
   }
@@ -6985,13 +6984,13 @@
    */
   Token validateModifiersForField(Modifiers modifiers) {
     if (modifiers.abstractKeyword != null) {
-      reportError12(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
+      reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
     }
     if (modifiers.externalKeyword != null) {
-      reportError13(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
+      reportError14(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
     }
     if (modifiers.factoryKeyword != null) {
-      reportError13(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
+      reportError14(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
     }
     Token staticKeyword = modifiers.staticKeyword;
     Token constKeyword = modifiers.constKeyword;
@@ -6999,23 +6998,23 @@
     Token varKeyword = modifiers.varKeyword;
     if (constKeyword != null) {
       if (finalKeyword != null) {
-        reportError13(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
+        reportError14(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
       }
       if (varKeyword != null) {
-        reportError13(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
+        reportError14(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
       }
       if (staticKeyword != null && constKeyword.offset < staticKeyword.offset) {
-        reportError13(ParserErrorCode.STATIC_AFTER_CONST, staticKeyword, []);
+        reportError14(ParserErrorCode.STATIC_AFTER_CONST, staticKeyword, []);
       }
     } else if (finalKeyword != null) {
       if (varKeyword != null) {
-        reportError13(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
+        reportError14(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
       }
       if (staticKeyword != null && finalKeyword.offset < staticKeyword.offset) {
-        reportError13(ParserErrorCode.STATIC_AFTER_FINAL, staticKeyword, []);
+        reportError14(ParserErrorCode.STATIC_AFTER_FINAL, staticKeyword, []);
       }
     } else if (varKeyword != null && staticKeyword != null && varKeyword.offset < staticKeyword.offset) {
-      reportError13(ParserErrorCode.STATIC_AFTER_VAR, staticKeyword, []);
+      reportError14(ParserErrorCode.STATIC_AFTER_VAR, staticKeyword, []);
     }
     return lexicallyFirst([constKeyword, finalKeyword, varKeyword]);
   }
@@ -7027,7 +7026,7 @@
    */
   void validateModifiersForFunctionDeclarationStatement(Modifiers modifiers) {
     if (modifiers.abstractKeyword != null || modifiers.constKeyword != null || modifiers.externalKeyword != null || modifiers.factoryKeyword != null || modifiers.finalKeyword != null || modifiers.staticKeyword != null || modifiers.varKeyword != null) {
-      reportError12(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, []);
+      reportError13(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, []);
     }
   }
 
@@ -7038,24 +7037,24 @@
    */
   void validateModifiersForGetterOrSetterOrMethod(Modifiers modifiers) {
     if (modifiers.abstractKeyword != null) {
-      reportError12(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
+      reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
     }
     if (modifiers.constKeyword != null) {
-      reportError13(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
+      reportError14(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
     }
     if (modifiers.factoryKeyword != null) {
-      reportError13(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
+      reportError14(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
     }
     if (modifiers.finalKeyword != null) {
-      reportError13(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
+      reportError14(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
     }
     if (modifiers.varKeyword != null) {
-      reportError13(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
+      reportError14(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
     }
     Token externalKeyword = modifiers.externalKeyword;
     Token staticKeyword = modifiers.staticKeyword;
     if (externalKeyword != null && staticKeyword != null && staticKeyword.offset < externalKeyword.offset) {
-      reportError13(ParserErrorCode.EXTERNAL_AFTER_STATIC, externalKeyword, []);
+      reportError14(ParserErrorCode.EXTERNAL_AFTER_STATIC, externalKeyword, []);
     }
   }
 
@@ -7066,22 +7065,22 @@
    */
   void validateModifiersForOperator(Modifiers modifiers) {
     if (modifiers.abstractKeyword != null) {
-      reportError12(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
+      reportError13(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
     }
     if (modifiers.constKeyword != null) {
-      reportError13(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
+      reportError14(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
     }
     if (modifiers.factoryKeyword != null) {
-      reportError13(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
+      reportError14(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
     }
     if (modifiers.finalKeyword != null) {
-      reportError13(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
+      reportError14(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
     }
     if (modifiers.staticKeyword != null) {
-      reportError13(ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword, []);
+      reportError14(ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword, []);
     }
     if (modifiers.varKeyword != null) {
-      reportError13(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
+      reportError14(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
     }
   }
 
@@ -7092,10 +7091,10 @@
    */
   void validateModifiersForTopLevelDeclaration(Modifiers modifiers) {
     if (modifiers.factoryKeyword != null) {
-      reportError13(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, modifiers.factoryKeyword, []);
+      reportError14(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, modifiers.factoryKeyword, []);
     }
     if (modifiers.staticKeyword != null) {
-      reportError13(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION, modifiers.staticKeyword, []);
+      reportError14(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION, modifiers.staticKeyword, []);
     }
   }
 
@@ -7107,16 +7106,16 @@
   void validateModifiersForTopLevelFunction(Modifiers modifiers) {
     validateModifiersForTopLevelDeclaration(modifiers);
     if (modifiers.abstractKeyword != null) {
-      reportError12(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, []);
+      reportError13(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, []);
     }
     if (modifiers.constKeyword != null) {
-      reportError13(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
+      reportError14(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
     }
     if (modifiers.finalKeyword != null) {
-      reportError13(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
+      reportError14(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
     }
     if (modifiers.varKeyword != null) {
-      reportError13(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
+      reportError14(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
     }
   }
 
@@ -7130,24 +7129,24 @@
   Token validateModifiersForTopLevelVariable(Modifiers modifiers) {
     validateModifiersForTopLevelDeclaration(modifiers);
     if (modifiers.abstractKeyword != null) {
-      reportError12(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE, []);
+      reportError13(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE, []);
     }
     if (modifiers.externalKeyword != null) {
-      reportError13(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
+      reportError14(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
     }
     Token constKeyword = modifiers.constKeyword;
     Token finalKeyword = modifiers.finalKeyword;
     Token varKeyword = modifiers.varKeyword;
     if (constKeyword != null) {
       if (finalKeyword != null) {
-        reportError13(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
+        reportError14(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
       }
       if (varKeyword != null) {
-        reportError13(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
+        reportError14(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
       }
     } else if (finalKeyword != null) {
       if (varKeyword != null) {
-        reportError13(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
+        reportError14(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
       }
     }
     return lexicallyFirst([constKeyword, finalKeyword, varKeyword]);
@@ -7162,19 +7161,19 @@
   void validateModifiersForTypedef(Modifiers modifiers) {
     validateModifiersForTopLevelDeclaration(modifiers);
     if (modifiers.abstractKeyword != null) {
-      reportError13(ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword, []);
+      reportError14(ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword, []);
     }
     if (modifiers.constKeyword != null) {
-      reportError13(ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword, []);
+      reportError14(ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword, []);
     }
     if (modifiers.externalKeyword != null) {
-      reportError13(ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword, []);
+      reportError14(ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword, []);
     }
     if (modifiers.finalKeyword != null) {
-      reportError13(ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword, []);
+      reportError14(ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword, []);
     }
     if (modifiers.varKeyword != null) {
-      reportError13(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword, []);
+      reportError14(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword, []);
     }
   }
 }
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 1c9e0cf..3e6f1aa 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -59,31 +59,6 @@
 
   static String _NG_TWO_WAY = "NgTwoWay";
 
-  /**
-   * Returns the array of all top-level Angular elements that could be used in this library.
-   *
-   * @param libraryElement the [LibraryElement] to analyze
-   * @return the array of all top-level Angular elements that could be used in this library
-   */
-  static List<AngularElement> getAngularElements(LibraryElement libraryElement) {
-    List<AngularElement> angularElements = [];
-    // add Angular elements from current library
-    for (CompilationUnitElement unit in libraryElement.units) {
-      for (ClassElement type in unit.types) {
-        addAngularElements(angularElements, type);
-      }
-    }
-    // handle imports
-    for (ImportElement importElement in libraryElement.imports) {
-      Namespace namespace = new NamespaceBuilder().createImportNamespace(importElement);
-      for (Element importedElement in namespace.definedNames.values) {
-        addAngularElements(angularElements, importedElement);
-      }
-    }
-    // done
-    return new List.from(angularElements);
-  }
-
   static Element getElement(ASTNode node, int offset) {
     // maybe node is not SimpleStringLiteral
     if (node is! SimpleStringLiteral) {
@@ -178,24 +153,6 @@
   }
 
   /**
-   * Adds [AngularElement] declared by the given top-level [Element].
-   *
-   * @param angularElements the list to fill with top-level [AngularElement]s
-   * @param unitMember the top-level member of unit, such as [ClassElement], to get
-   *          [AngularElement]s from
-   */
-  static void addAngularElements(List<AngularElement> angularElements, Element unitMember) {
-    if (unitMember is ClassElement) {
-      ClassElement type = unitMember;
-      for (ToolkitObjectElement toolkitObject in type.toolkitObjects) {
-        if (toolkitObject is AngularElement) {
-          angularElements.add(toolkitObject);
-        }
-      }
-    }
-  }
-
-  /**
    * Returns the [FieldElement] of the first field in the given [FieldDeclaration].
    */
   static FieldElement getOnlyFieldElement(FieldDeclaration fieldDeclaration) {
@@ -248,11 +205,6 @@
   }
 
   /**
-   * The [AnalysisContext] that performs analysis.
-   */
-  AnalysisContext _context;
-
-  /**
    * The listener to which errors will be reported.
    */
   AnalysisErrorListener _errorListener;
@@ -288,8 +240,7 @@
    * @param errorListener the listener to which errors will be reported.
    * @param source the source containing the unit that will be analyzed
    */
-  AngularCompilationUnitBuilder(AnalysisContext context, AnalysisErrorListener errorListener, Source source) {
-    this._context = context;
+  AngularCompilationUnitBuilder(AnalysisErrorListener errorListener, Source source) {
     this._errorListener = errorListener;
     this._source = source;
   }
@@ -446,33 +397,10 @@
     }
     // create
     if (isValid) {
-      AngularComponentElementImpl element = new AngularComponentElementImpl(name, nameOffset);
+      AngularComponentElementImpl element = new AngularComponentElementImpl(name, nameOffset, _annotation.offset);
       element.selector = selector;
       element.templateUri = templateUri;
       element.templateUriOffset = templateUriOffset;
-      // resolve template URI
-      // TODO(scheglov) resolve to HtmlElement to allow F3 ?
-      if (templateUri != null) {
-        try {
-          parseUriWithException(templateUri);
-          // TODO(scheglov) think if there is better solution
-          if (templateUri.startsWith("packages/")) {
-            templateUri = "package:${templateUri.substring("packages/".length)}";
-          }
-          Source templateSource = _context.sourceFactory.resolveUri(_source, templateUri);
-          if (templateSource == null || !templateSource.exists()) {
-            templateSource = _context.sourceFactory.resolveUri(_source, "package:${templateUri}");
-          }
-          if (templateSource == null || !templateSource.exists()) {
-            reportErrorForArgument(_TEMPLATE_URL, AngularCode.URI_DOES_NOT_EXIST, [templateUri]);
-          }
-          if (AnalysisEngine.isHtmlFileName(templateUri)) {
-            element.templateSource = templateSource;
-          }
-        } on URISyntaxException catch (exception) {
-          reportErrorForArgument(_TEMPLATE_URL, AngularCode.INVALID_URI, [templateUri]);
-        }
-      }
       element.styleUri = styleUri;
       element.styleUriOffset = styleUriOffset;
       element.properties = parseNgComponentProperties(true);
@@ -1891,12 +1819,6 @@
   int _modificationStamp = 0;
 
   /**
-   * The line information associated with the source for which an element is being built, or
-   * `null` if we are not building an element.
-   */
-  LineInfo _lineInfo;
-
-  /**
    * The HTML element being built.
    */
   HtmlElementImpl _htmlElement;
@@ -1946,7 +1868,6 @@
    */
   HtmlElementImpl buildHtmlElement2(Source source, int modificationStamp, ht.HtmlUnit unit) {
     this._modificationStamp = modificationStamp;
-    _lineInfo = _context.computeLineInfo(source);
     HtmlElementImpl result = new HtmlElementImpl(_context, source.shortName);
     result.source = source;
     _htmlElement = result;
@@ -1989,7 +1910,7 @@
           _errorListener.addAll(resolver.errorListener);
         } on AnalysisException catch (exception) {
           //TODO (danrubel): Handle or forward the exception
-          AnalysisEngine.instance.logger.logError3(exception);
+          AnalysisEngine.instance.logger.logError2("Could not resolve script tag", exception);
         }
         node.scriptElement = script;
         _scripts.add(script);
@@ -2032,12 +1953,7 @@
     return null;
   }
 
-  Object visitXmlAttributeNode(ht.XmlAttributeNode node) {
-    for (ht.EmbeddedExpression expression in node.expressions) {
-      resolveExpression(expression.expression);
-    }
-    return null;
-  }
+  Object visitXmlAttributeNode(ht.XmlAttributeNode node) => null;
 
   Object visitXmlTagNode(ht.XmlTagNode node) {
     if (_parentNodes.contains(node)) {
@@ -2045,9 +1961,6 @@
     }
     _parentNodes.add(node);
     try {
-      for (ht.EmbeddedExpression expression in node.expressions) {
-        resolveExpression(expression.expression);
-      }
       node.visitChildren(this);
     } finally {
       _parentNodes.remove(node);
@@ -2125,9 +2038,6 @@
     int length = attribute.valueToken.length - 2;
     reportError(errorCode, offset, length, arguments);
   }
-
-  void resolveExpression(Expression expression) {
-  }
 }
 
 /**
@@ -2196,6 +2106,8 @@
     sc.TokenType operatorType = node.operator.type;
     if (operatorType != sc.TokenType.EQ) {
       checkForDeprecatedMemberUse(node.bestElement, node);
+    } else {
+      checkForUseOfVoidResult(node.rightHandSide);
     }
     return super.visitAssignmentExpression(node);
   }
@@ -2280,6 +2192,11 @@
     return super.visitSuperConstructorInvocation(node);
   }
 
+  Object visitVariableDeclaration(VariableDeclaration node) {
+    checkForUseOfVoidResult(node.initializer);
+    return super.visitVariableDeclaration(node);
+  }
+
   /**
    * Check for the passed is expression for the unnecessary type check hint codes as well as null
    * checks expressed using an is expression.
@@ -2435,7 +2352,28 @@
    * @return `true` if and only if a hint code is generated on the passed node
    * @see HintCode#MISSING_RETURN
    */
-  bool checkForMissingReturn(TypeName returnType, FunctionBody body) => false;
+  bool checkForMissingReturn(TypeName returnType, FunctionBody body) {
+    // Check that the method or function has a return type, and a function body
+    if (returnType == null || body == null) {
+      return false;
+    }
+    // Check that the body is a BlockFunctionBody
+    if (body is! BlockFunctionBody) {
+      return false;
+    }
+    // Check that the type is resolvable, and is not "void"
+    Type2 returnTypeType = returnType.type;
+    if (returnTypeType == null || returnTypeType.isVoid) {
+      return false;
+    }
+    // Check the block for a return statement, if not, create the hint
+    BlockFunctionBody blockFunctionBody = body as BlockFunctionBody;
+    if (!blockFunctionBody.accept(new ExitDetector())) {
+      _errorReporter.reportError3(HintCode.MISSING_RETURN, returnType, [returnTypeType.displayName]);
+      return true;
+    }
+    return false;
+  }
 
   /**
    * Check for the passed class declaration for the
@@ -2550,6 +2488,30 @@
     }
     return false;
   }
+
+  /**
+   * Check for situations where the result of a method or function is used, when it returns 'void'.
+   *
+   * TODO(jwren) Many other situations of use could be covered. We currently cover the cases var x =
+   * m() and x = m(), but we could also cover cases such as m().x, m()[k], a + m(), f(m()), return
+   * m().
+   *
+   * @param node expression on the RHS of some assignment
+   * @return `true` if and only if a hint code is generated on the passed node
+   * @see HintCode#USE_OF_VOID_RESULT
+   */
+  bool checkForUseOfVoidResult(Expression expression) {
+    if (expression == null || expression is! MethodInvocation) {
+      return false;
+    }
+    MethodInvocation methodInvocation = expression as MethodInvocation;
+    if (identical(methodInvocation.staticType, VoidTypeImpl.instance)) {
+      SimpleIdentifier methodName = methodInvocation.methodName;
+      _errorReporter.reportError3(HintCode.USE_OF_VOID_RESULT, methodName, [methodName.name]);
+      return true;
+    }
+    return false;
+  }
 }
 
 /**
@@ -3019,11 +2981,20 @@
     Expression conditionExpression = node.condition;
     Statement thenStatement = node.thenStatement;
     Statement elseStatement = node.elseStatement;
-    // TODO(jwren) Do we want to take constant expressions into account, evaluate if(false) {}
-    // differently than if(<condition>), when <condition> evaluates to a constant false value?
     if (conditionExpression.accept(this)) {
       return true;
     }
+    // TODO(jwren) Do we want to take all constant expressions into account?
+    if (conditionExpression is BooleanLiteral) {
+      BooleanLiteral booleanLiteral = conditionExpression;
+      if (booleanLiteral.value) {
+        // if(true) ...
+        return thenStatement.accept(this);
+      } else if (elseStatement != null) {
+        // if (false) ...
+        return elseStatement.accept(this);
+      }
+    }
     if (thenStatement == null || elseStatement == null) {
       return false;
     }
@@ -3031,7 +3002,7 @@
   }
 
   bool visitIndexExpression(IndexExpression node) {
-    Expression target = node.target;
+    Expression target = node.realTarget;
     if (target != null && target.accept(this)) {
       return true;
     }
@@ -3052,7 +3023,7 @@
   bool visitLiteral(Literal node) => false;
 
   bool visitMethodInvocation(MethodInvocation node) {
-    Expression target = node.target;
+    Expression target = node.realTarget;
     if (target != null && target.accept(this)) {
       return true;
     }
@@ -3067,7 +3038,13 @@
 
   bool visitPrefixExpression(PrefixExpression node) => false;
 
-  bool visitPropertyAccess(PropertyAccess node) => node.target.accept(this);
+  bool visitPropertyAccess(PropertyAccess node) {
+    Expression target = node.realTarget;
+    if (target != null && target.accept(this)) {
+      return true;
+    }
+    return false;
+  }
 
   bool visitRethrowExpression(RethrowExpression node) => true;
 
@@ -3081,12 +3058,21 @@
 
   bool visitSwitchStatement(SwitchStatement node) {
     bool hasDefault = false;
-    for (SwitchMember member in node.members) {
-      if (!member.accept(this)) {
-        return false;
-      }
-      if (member is SwitchDefault) {
+    NodeList<SwitchMember> memberList = node.members;
+    List<SwitchMember> members = new List.from(memberList);
+    for (int i = 0; i < members.length; i++) {
+      SwitchMember switchMember = members[i];
+      if (switchMember is SwitchDefault) {
         hasDefault = true;
+        // If this is the last member and there are no statements, return false
+        if (switchMember.statements.isEmpty && i + 1 == members.length) {
+          return false;
+        }
+      }
+      // For switch members with no statements, don't visit the children, otherwise, return false if
+      // no return is found in the children statements
+      if (!switchMember.statements.isEmpty && !switchMember.accept(this)) {
+        return false;
       }
     }
     return hasDefault;
@@ -3435,6 +3421,9 @@
   }
 
   Object visitPrefixedIdentifier(PrefixedIdentifier node) {
+    if (_unusedImports.isEmpty) {
+      return null;
+    }
     // If the prefixed identifier references some A.B, where A is a library prefix, then we can
     // lookup the associated ImportDirective in prefixElementMap and remove it from the
     // unusedImports list.
@@ -3448,7 +3437,12 @@
     return visitIdentifier(element, prefixIdentifier.name);
   }
 
-  Object visitSimpleIdentifier(SimpleIdentifier node) => visitIdentifier(node.staticElement, node.name);
+  Object visitSimpleIdentifier(SimpleIdentifier node) {
+    if (_unusedImports.isEmpty) {
+      return null;
+    }
+    return visitIdentifier(node.staticElement, node.name);
+  }
 
   void set inDefiningCompilationUnit(bool inDefiningCompilationUnit) {
     this._inDefiningCompilationUnit = inDefiningCompilationUnit;
@@ -3519,6 +3513,11 @@
     } else if (element is PrefixElement) {
       _unusedImports.remove(_prefixElementMap[element]);
       return null;
+    } else if (element.enclosingElement is! CompilationUnitElement) {
+      // Identifiers that aren't a prefix element and whose enclosing element isn't a
+      // CompilationUnit are ignored- this covers the case the identifier is a relative-reference,
+      // a reference to an identifier not imported by this library.
+      return null;
     }
     LibraryElement containingLibrary = element.library;
     if (containingLibrary == null) {
@@ -5174,7 +5173,7 @@
     SimpleIdentifier labelNode = node.label;
     LabelElementImpl labelElement = lookupLabel(node, labelNode);
     if (labelElement != null && labelElement.isOnSwitchMember) {
-      _resolver.reportError8(ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, labelNode, []);
+      _resolver.reportError9(ResolverErrorCode.BREAK_LABEL_ON_SWITCH_MEMBER, labelNode, []);
     }
     return null;
   }
@@ -5300,9 +5299,9 @@
     FieldElement fieldElement = enclosingClass.getField(fieldName.name);
     fieldName.staticElement = fieldElement;
     if (fieldElement == null || fieldElement.isSynthetic) {
-      _resolver.reportError8(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+      _resolver.reportError9(CompileTimeErrorCode.INITIALIZER_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
     } else if (fieldElement.isStatic) {
-      _resolver.reportError8(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, node, [fieldName]);
+      _resolver.reportError9(CompileTimeErrorCode.INITIALIZER_FOR_STATIC_FIELD, node, [fieldName]);
     }
     return null;
   }
@@ -5340,7 +5339,7 @@
     SimpleIdentifier labelNode = node.label;
     LabelElementImpl labelElement = lookupLabel(node, labelNode);
     if (labelElement != null && labelElement.isOnSwitchStatement) {
-      _resolver.reportError8(ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNode, []);
+      _resolver.reportError9(ResolverErrorCode.CONTINUE_LABEL_ON_SWITCH, labelNode, []);
     }
     return null;
   }
@@ -5368,7 +5367,7 @@
     if (classElement != null) {
       FieldElement fieldElement = classElement.getField(fieldName);
       if (fieldElement == null || fieldElement.isSynthetic) {
-        _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+        _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
       } else {
         ParameterElement parameterElement = node.element;
         if (parameterElement is FieldFormalParameterElementImpl) {
@@ -5376,17 +5375,17 @@
           Type2 declaredType = fieldFormal.type;
           Type2 fieldType = fieldElement.type;
           if (fieldElement.isSynthetic) {
-            _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+            _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
           } else if (fieldElement.isStatic) {
-            _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
+            _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
           } else if (declaredType != null && fieldType != null && !declaredType.isAssignableTo(fieldType)) {
-            _resolver.reportError8(StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, node, [declaredType.displayName, fieldType.displayName]);
+            _resolver.reportError9(StaticWarningCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, node, [declaredType.displayName, fieldType.displayName]);
           }
         } else {
           if (fieldElement.isSynthetic) {
-            _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
+            _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_NON_EXISTANT_FIELD, node, [fieldName]);
           } else if (fieldElement.isStatic) {
-            _resolver.reportError8(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
+            _resolver.reportError9(CompileTimeErrorCode.INITIALIZING_FORMAL_FOR_STATIC_FIELD, node, [fieldName]);
           }
         }
       }
@@ -5612,9 +5611,9 @@
       return null;
     }
     if (identical(errorCode, StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION)) {
-      _resolver.reportError8(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName, [methodName.name]);
+      _resolver.reportError9(StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION, methodName, [methodName.name]);
     } else if (identical(errorCode, CompileTimeErrorCode.UNDEFINED_FUNCTION)) {
-      _resolver.reportError8(CompileTimeErrorCode.UNDEFINED_FUNCTION, methodName, [methodName.name]);
+      _resolver.reportError9(CompileTimeErrorCode.UNDEFINED_FUNCTION, methodName, [methodName.name]);
     } else if (identical(errorCode, StaticTypeWarningCode.UNDEFINED_METHOD)) {
       String targetTypeName;
       if (target == null) {
@@ -5650,7 +5649,7 @@
       // The error code will never be generated via type propagation
       Type2 targetType = getStaticType(target);
       String targetTypeName = targetType == null ? null : targetType.name;
-      _resolver.reportError8(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD, methodName, [methodName.name, targetTypeName]);
+      _resolver.reportError9(StaticTypeWarningCode.UNDEFINED_SUPER_METHOD, methodName, [methodName.name, targetTypeName]);
     }
     return null;
   }
@@ -5708,13 +5707,13 @@
       }
       if (element == null) {
         if (identifier.inSetterContext()) {
-          _resolver.reportError8(StaticWarningCode.UNDEFINED_SETTER, identifier, [identifier.name, prefixElement.name]);
+          _resolver.reportError9(StaticWarningCode.UNDEFINED_SETTER, identifier, [identifier.name, prefixElement.name]);
         } else if (node.parent is Annotation) {
           Annotation annotation = node.parent as Annotation;
-          _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+          _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
           return null;
         } else {
-          _resolver.reportError8(StaticWarningCode.UNDEFINED_GETTER, identifier, [identifier.name, prefixElement.name]);
+          _resolver.reportError9(StaticWarningCode.UNDEFINED_GETTER, identifier, [identifier.name, prefixElement.name]);
         }
         return null;
       }
@@ -5856,17 +5855,17 @@
     Element element = resolveSimpleIdentifier(node);
     ClassElement enclosingClass = _resolver.enclosingClass;
     if (isFactoryConstructorReturnType(node) && element != enclosingClass) {
-      _resolver.reportError8(CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node, []);
+      _resolver.reportError9(CompileTimeErrorCode.INVALID_FACTORY_NAME_NOT_A_CLASS, node, []);
     } else if (isConstructorReturnType(node) && element != enclosingClass) {
-      _resolver.reportError8(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
+      _resolver.reportError9(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
       element = null;
     } else if (element == null || (element is PrefixElement && !isValidAsPrefix(node))) {
       // TODO(brianwilkerson) Recover from this error.
       if (isConstructorReturnType(node)) {
-        _resolver.reportError8(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
+        _resolver.reportError9(CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node, []);
       } else if (node.parent is Annotation) {
         Annotation annotation = node.parent as Annotation;
-        _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+        _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
       } else {
         _resolver.reportErrorProxyConditionalAnalysisError(_resolver.enclosingClass, StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
       }
@@ -5903,14 +5902,14 @@
     ConstructorElement element = superType.lookUpConstructor(superName, _definingLibrary);
     if (element == null) {
       if (name != null) {
-        _resolver.reportError8(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, node, [superType.displayName, name]);
+        _resolver.reportError9(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER, node, [superType.displayName, name]);
       } else {
-        _resolver.reportError8(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT, node, [superType.displayName]);
+        _resolver.reportError9(CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT, node, [superType.displayName]);
       }
       return null;
     } else {
       if (element.isFactory) {
-        _resolver.reportError8(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node, [element]);
+        _resolver.reportError9(CompileTimeErrorCode.NON_GENERATIVE_CONSTRUCTOR, node, [element]);
       }
     }
     if (name != null) {
@@ -5927,7 +5926,7 @@
 
   Object visitSuperExpression(SuperExpression node) {
     if (!isSuperInValidContext(node)) {
-      _resolver.reportError8(CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node, []);
+      _resolver.reportError9(CompileTimeErrorCode.SUPER_IN_INVALID_CONTEXT, node, []);
     }
     return super.visitSuperExpression(node);
   }
@@ -6483,11 +6482,11 @@
       }
     } else {
       if (labelScope == null) {
-        _resolver.reportError8(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
+        _resolver.reportError9(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
       } else {
         labelElement = labelScope.lookup(labelNode) as LabelElementImpl;
         if (labelElement == null) {
-          _resolver.reportError8(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
+          _resolver.reportError9(CompileTimeErrorCode.LABEL_UNDEFINED, labelNode, [labelNode.name]);
         } else {
           labelNode.staticElement = labelElement;
         }
@@ -6496,7 +6495,7 @@
     if (labelElement != null) {
       ExecutableElement labelContainer = labelElement.getAncestor(ExecutableElement);
       if (labelContainer != _resolver.enclosingFunction) {
-        _resolver.reportError8(CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE, labelNode, [labelNode.name]);
+        _resolver.reportError9(CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE, labelNode, [labelNode.name]);
         labelElement = null;
       }
     }
@@ -6821,7 +6820,7 @@
     }
     // we need constructor
     if (constructor == null) {
-      _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+      _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
       return;
     }
     // record element
@@ -6833,13 +6832,13 @@
   void resolveAnnotationElementGetter(Annotation annotation, PropertyAccessorElement accessorElement) {
     // accessor should be synthetic
     if (!accessorElement.isSynthetic) {
-      _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+      _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
       return;
     }
     // variable should be constant
     VariableElement variableElement = accessorElement.variable;
     if (!variableElement.isConst) {
-      _resolver.reportError8(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
+      _resolver.reportError9(CompileTimeErrorCode.INVALID_ANNOTATION, annotation, []);
     }
     // OK
     return;
@@ -6906,13 +6905,13 @@
         ParameterElement element = namedParameters[name];
         if (element == null) {
           ErrorCode errorCode = (reportError ? CompileTimeErrorCode.UNDEFINED_NAMED_PARAMETER : StaticWarningCode.UNDEFINED_NAMED_PARAMETER) as ErrorCode;
-          _resolver.reportError8(errorCode, nameNode, [name]);
+          _resolver.reportError9(errorCode, nameNode, [name]);
         } else {
           resolvedParameters[i] = element;
           nameNode.staticElement = element;
         }
         if (!usedNames.add(name)) {
-          _resolver.reportError8(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
+          _resolver.reportError9(CompileTimeErrorCode.DUPLICATE_NAMED_ARGUMENT, nameNode, [name]);
         }
       } else {
         positionalArgumentCount++;
@@ -6923,10 +6922,10 @@
     }
     if (positionalArgumentCount < requiredParameters.length) {
       ErrorCode errorCode = (reportError ? CompileTimeErrorCode.NOT_ENOUGH_REQUIRED_ARGUMENTS : StaticWarningCode.NOT_ENOUGH_REQUIRED_ARGUMENTS) as ErrorCode;
-      _resolver.reportError8(errorCode, argumentList, [requiredParameters.length, positionalArgumentCount]);
+      _resolver.reportError9(errorCode, argumentList, [requiredParameters.length, positionalArgumentCount]);
     } else if (positionalArgumentCount > unnamedParameterCount) {
       ErrorCode errorCode = (reportError ? CompileTimeErrorCode.EXTRA_POSITIONAL_ARGUMENTS : StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS) as ErrorCode;
-      _resolver.reportError8(errorCode, argumentList, [unnamedParameterCount, positionalArgumentCount]);
+      _resolver.reportError9(errorCode, argumentList, [unnamedParameterCount, positionalArgumentCount]);
     }
     return resolvedParameters;
   }
@@ -7123,6 +7122,17 @@
       }
     }
     if (shouldReportMissingMember_static || shouldReportMissingMember_propagated) {
+      if (staticType.isVoid) {
+        if (propertyName.inSetterContext()) {
+          ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_SETTER : HintCode.UNDEFINED_SETTER) as ErrorCode;
+          _resolver.reportError9(errorCode, propertyName, [propertyName.name, staticType.displayName]);
+        } else if (propertyName.inGetterContext()) {
+          ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_GETTER : HintCode.UNDEFINED_GETTER) as ErrorCode;
+          _resolver.reportError9(errorCode, propertyName, [propertyName.name, staticType.displayName]);
+        } else {
+          _resolver.reportError9(StaticWarningCode.UNDEFINED_IDENTIFIER, propertyName, [propertyName.name]);
+        }
+      }
       Element staticOrPropagatedEnclosingElt = shouldReportMissingMember_static ? staticType.element : propagatedType.element;
       if (staticOrPropagatedEnclosingElt != null) {
         bool isStaticProperty = isStatic(staticOrPropagatedEnclosingElt);
@@ -8098,11 +8108,6 @@
   LibraryScope _libraryScope;
 
   /**
-   * An array of all top-level Angular elements that could be used in this library.
-   */
-  List<AngularElement> angularElements;
-
-  /**
    * An empty array that can be used to initialize lists of libraries.
    */
   static List<Library> _EMPTY_ARRAY = new List<Library>(0);
@@ -9242,11 +9247,8 @@
     try {
       for (Source source in library.compilationUnitSources) {
         CompilationUnit ast = library.getAST(source);
-        new AngularCompilationUnitBuilder(analysisContext, _errorListener, source).build(ast);
+        new AngularCompilationUnitBuilder(_errorListener, source).build(ast);
       }
-      // remember accessible Angular elements
-      LibraryElementImpl libraryElement = library.libraryElement;
-      library.angularElements = AngularCompilationUnitBuilder.getAngularElements(libraryElement);
     } finally {
       timeCounter.stop();
     }
@@ -11157,7 +11159,7 @@
    * @param node the node specifying the location of the error
    * @param arguments the arguments to the error, used to compose the error message
    */
-  void reportError8(ErrorCode errorCode, ASTNode node, List<Object> arguments) {
+  void reportError9(ErrorCode errorCode, ASTNode node, List<Object> arguments) {
     _errorListener.onError(new AnalysisError.con2(source, node.offset, node.length, errorCode, arguments));
   }
 
@@ -11169,7 +11171,7 @@
    * @param length the length of the location of the error
    * @param arguments the arguments to the error, used to compose the error message
    */
-  void reportError9(ErrorCode errorCode, int offset, int length, List<Object> arguments) {
+  void reportError10(ErrorCode errorCode, int offset, int length, List<Object> arguments) {
     _errorListener.onError(new AnalysisError.con2(source, offset, length, errorCode, arguments));
   }
 
@@ -11180,7 +11182,7 @@
    * @param token the token specifying the location of the error
    * @param arguments the arguments to the error, used to compose the error message
    */
-  void reportError10(ErrorCode errorCode, sc.Token token, List<Object> arguments) {
+  void reportError11(ErrorCode errorCode, sc.Token token, List<Object> arguments) {
     _errorListener.onError(new AnalysisError.con2(source, token.offset, token.length, errorCode, arguments));
   }
 
@@ -12322,20 +12324,28 @@
    */
   Object visitPropertyAccess(PropertyAccess node) {
     SimpleIdentifier propertyName = node.propertyName;
-    Element element = propertyName.staticElement;
+    Element staticElement = propertyName.staticElement;
     Type2 staticType = _dynamicType;
-    if (element is MethodElement) {
-      staticType = element.type;
-    } else if (element is PropertyAccessorElement) {
-      staticType = getType(element, node.target != null ? getStaticType(node.target) : null);
+    if (staticElement is MethodElement) {
+      staticType = staticElement.type;
+    } else if (staticElement is PropertyAccessorElement) {
+      Expression realTarget = node.realTarget;
+      staticType = getType(staticElement, realTarget != null ? getStaticType(realTarget) : null);
     } else {
     }
     recordStaticType(propertyName, staticType);
     recordStaticType(node, staticType);
-    // TODO(brianwilkerson) I think we want to repeat the logic above using the propagated element
-    // to get another candidate for the propagated type.
-    Type2 propagatedType = _overrideManager.getType(element);
+    Element propagatedElement = propertyName.propagatedElement;
+    Type2 propagatedType = _overrideManager.getType(propagatedElement);
+    if (propagatedElement is MethodElement) {
+      propagatedType = propagatedElement.type;
+    } else if (propagatedElement is PropertyAccessorElement) {
+      Expression realTarget = node.realTarget;
+      propagatedType = getType(propagatedElement, realTarget != null ? realTarget.bestType : null);
+    } else {
+    }
     if (propagatedType != null && propagatedType.isMoreSpecificThan(staticType)) {
+      recordPropagatedType2(propertyName, propagatedType);
       recordPropagatedType2(node, propagatedType);
     }
     return null;
@@ -14056,10 +14066,10 @@
             if (parent.parent is InstanceCreationExpression && (parent.parent as InstanceCreationExpression).isConst) {
               // If, if this is a const expression, then generate a
               // CompileTimeErrorCode.CONST_WITH_NON_TYPE error.
-              reportError8(CompileTimeErrorCode.CONST_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
+              reportError9(CompileTimeErrorCode.CONST_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
             } else {
               // Else, if this expression is a new expression, report a NEW_WITH_NON_TYPE warning.
-              reportError8(StaticWarningCode.NEW_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
+              reportError9(StaticWarningCode.NEW_WITH_NON_TYPE, prefixedIdentifier.identifier, [prefixedIdentifier.identifier.name]);
             }
             setElement(prefix, element);
             return null;
@@ -14085,14 +14095,14 @@
       InstanceCreationExpression creation = node.parent.parent as InstanceCreationExpression;
       if (creation.isConst) {
         if (element == null) {
-          reportError8(CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
+          reportError9(CompileTimeErrorCode.UNDEFINED_CLASS, typeNameSimple, [typeName]);
         } else {
-          reportError8(CompileTimeErrorCode.CONST_WITH_NON_TYPE, typeNameSimple, [typeName]);
+          reportError9(CompileTimeErrorCode.CONST_WITH_NON_TYPE, typeNameSimple, [typeName]);
         }
         elementValid = false;
       } else {
         if (element != null) {
-          reportError8(StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
+          reportError9(StaticWarningCode.NEW_WITH_NON_TYPE, typeNameSimple, [typeName]);
           elementValid = false;
         }
       }
@@ -14105,22 +14115,22 @@
       SimpleIdentifier typeNameSimple = getTypeSimpleIdentifier(typeName);
       RedirectingConstructorKind redirectingConstructorKind;
       if (isBuiltInIdentifier(node) && isTypeAnnotation(node)) {
-        reportError8(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, typeName, [typeName.name]);
+        reportError9(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, typeName, [typeName.name]);
       } else if (typeNameSimple.name == "boolean") {
-        reportError8(StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
+        reportError9(StaticWarningCode.UNDEFINED_CLASS_BOOLEAN, typeNameSimple, []);
       } else if (isTypeNameInCatchClause(node)) {
-        reportError8(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [typeName.name]);
+        reportError9(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [typeName.name]);
       } else if (isTypeNameInAsExpression(node)) {
-        reportError8(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
+        reportError9(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
       } else if (isTypeNameInIsExpression(node)) {
-        reportError8(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.name]);
+        reportError9(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.name]);
       } else if ((redirectingConstructorKind = getRedirectingConstructorKind(node)) != null) {
         ErrorCode errorCode = (identical(redirectingConstructorKind, RedirectingConstructorKind.CONST) ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS : StaticWarningCode.REDIRECT_TO_NON_CLASS) as ErrorCode;
-        reportError8(errorCode, typeName, [typeName.name]);
+        reportError9(errorCode, typeName, [typeName.name]);
       } else if (isTypeNameInTypeArgumentList(node)) {
-        reportError8(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName, [typeName.name]);
+        reportError9(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName, [typeName.name]);
       } else {
-        reportError8(StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
+        reportError9(StaticWarningCode.UNDEFINED_CLASS, typeName, [typeName.name]);
       }
       elementValid = false;
     }
@@ -14156,16 +14166,16 @@
       // The name does not represent a type.
       RedirectingConstructorKind redirectingConstructorKind;
       if (isTypeNameInCatchClause(node)) {
-        reportError8(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [typeName.name]);
+        reportError9(StaticWarningCode.NON_TYPE_IN_CATCH_CLAUSE, typeName, [typeName.name]);
       } else if (isTypeNameInAsExpression(node)) {
-        reportError8(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
+        reportError9(StaticWarningCode.CAST_TO_NON_TYPE, typeName, [typeName.name]);
       } else if (isTypeNameInIsExpression(node)) {
-        reportError8(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.name]);
+        reportError9(StaticWarningCode.TYPE_TEST_NON_TYPE, typeName, [typeName.name]);
       } else if ((redirectingConstructorKind = getRedirectingConstructorKind(node)) != null) {
         ErrorCode errorCode = (identical(redirectingConstructorKind, RedirectingConstructorKind.CONST) ? CompileTimeErrorCode.REDIRECT_TO_NON_CLASS : StaticWarningCode.REDIRECT_TO_NON_CLASS) as ErrorCode;
-        reportError8(errorCode, typeName, [typeName.name]);
+        reportError9(errorCode, typeName, [typeName.name]);
       } else if (isTypeNameInTypeArgumentList(node)) {
-        reportError8(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName, [typeName.name]);
+        reportError9(StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT, typeName, [typeName.name]);
       } else {
         ASTNode parent = typeName.parent;
         while (parent is TypeName) {
@@ -14173,7 +14183,7 @@
         }
         if (parent is ExtendsClause || parent is ImplementsClause || parent is WithClause || parent is ClassTypeAlias) {
         } else {
-          reportError8(StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
+          reportError9(StaticWarningCode.NOT_A_TYPE, typeName, [typeName.name]);
         }
       }
       setElement(typeName, this._dynamicType.element);
@@ -14195,7 +14205,7 @@
         }
       }
       if (argumentCount != parameterCount) {
-        reportError8(getInvalidTypeParametersErrorCode(node), node, [typeName.name, parameterCount, argumentCount]);
+        reportError9(getInvalidTypeParametersErrorCode(node), node, [typeName.name, parameterCount, argumentCount]);
       }
       argumentCount = typeArguments.length;
       if (argumentCount < parameterCount) {
@@ -14593,7 +14603,7 @@
             Element element2 = identifier2.staticElement;
             if (element != null && element == element2) {
               detectedRepeatOnIndex[j] = true;
-              reportError8(CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
+              reportError9(CompileTimeErrorCode.IMPLEMENTS_REPEATED, typeName2, [name2]);
             }
           }
         }
@@ -14618,9 +14628,9 @@
     // If the type is not an InterfaceType, then visitTypeName() sets the type to be a DynamicTypeImpl
     Identifier name = typeName.name;
     if (name.name == sc.Keyword.DYNAMIC.syntax) {
-      reportError8(dynamicTypeError, name, [name.name]);
+      reportError9(dynamicTypeError, name, [name.name]);
     } else {
-      reportError8(nonTypeError, name, [name.name]);
+      reportError9(nonTypeError, name, [name.name]);
     }
     return null;
   }
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index cc29c4b..bb33c66 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -217,7 +217,7 @@
    * @param offsetDelta the offset from the beginning of the file to the beginning of the source
    *          being scanned
    */
-  SubSequenceReader(CharSequence sequence, int offsetDelta) : super(sequence) {
+  SubSequenceReader(String sequence, int offsetDelta) : super(sequence) {
     this._offsetDelta = offsetDelta;
   }
 
@@ -493,7 +493,7 @@
   /**
    * The sequence from which characters will be read.
    */
-  CharSequence _sequence;
+  String _sequence;
 
   /**
    * The number of characters in the string.
@@ -510,9 +510,9 @@
    *
    * @param sequence the sequence from which characters will be read
    */
-  CharSequenceReader(CharSequence sequence) {
+  CharSequenceReader(String sequence) {
     this._sequence = sequence;
-    this._stringLength = sequence.length();
+    this._stringLength = sequence.length;
     this._charOffset = -1;
   }
 
@@ -520,18 +520,18 @@
     if (_charOffset + 1 >= _stringLength) {
       return -1;
     }
-    return _sequence.charAt(++_charOffset);
+    return _sequence.codeUnitAt(++_charOffset);
   }
 
   int get offset => _charOffset;
 
-  String getString(int start, int endDelta) => _sequence.subSequence(start, _charOffset + 1 + endDelta).toString();
+  String getString(int start, int endDelta) => _sequence.substring(start, _charOffset + 1 + endDelta).toString();
 
   int peek() {
-    if (_charOffset + 1 >= _sequence.length()) {
+    if (_charOffset + 1 >= _sequence.length) {
       return -1;
     }
-    return _sequence.charAt(_charOffset + 1);
+    return _sequence.codeUnitAt(_charOffset + 1);
   }
 
   void set offset(int offset) {
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index c083950..896a15d 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -384,12 +384,12 @@
    * Read all of the configuration files to initialize the library maps.
    */
   void initializeLibraryMap() {
+    JavaFile librariesFile = new JavaFile.relative(new JavaFile.relative(libraryDirectory, _INTERNAL_DIR), _LIBRARIES_FILE);
     try {
-      JavaFile librariesFile = new JavaFile.relative(new JavaFile.relative(libraryDirectory, _INTERNAL_DIR), _LIBRARIES_FILE);
       String contents = librariesFile.readAsStringSync();
       _libraryMap = new SdkLibrariesReader().readFrom(librariesFile, contents);
     } on JavaException catch (exception) {
-      AnalysisEngine.instance.logger.logError3(exception);
+      AnalysisEngine.instance.logger.logError2("Could not initialize the library map from ${librariesFile.getAbsolutePath()}", exception);
       _libraryMap = new LibraryMap();
     }
   }
@@ -448,7 +448,7 @@
    */
   LibraryMap readFrom2(Source source, String libraryFileContents) {
     BooleanErrorListener errorListener = new BooleanErrorListener();
-    Scanner scanner = new Scanner(source, new CharSequenceReader(new CharSequence(libraryFileContents)), errorListener);
+    Scanner scanner = new Scanner(source, new CharSequenceReader(libraryFileContents), errorListener);
     Parser parser = new Parser(source, errorListener);
     CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
     SdkLibrariesReader_LibraryBuilder libraryBuilder = new SdkLibrariesReader_LibraryBuilder();
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index fc9d672..af3110c 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -455,20 +455,12 @@
  */
 abstract class Source_ContentReceiver {
   /**
-   * Accept the contents of a source represented as a character buffer.
+   * Accept the contents of a source.
    *
    * @param contents the contents of the source
    * @param modificationTime the time at which the contents were last set
    */
-  void accept(CharBuffer contents, int modificationTime);
-
-  /**
-   * Accept the contents of a source represented as a string.
-   *
-   * @param contents the contents of the source
-   * @param modificationTime the time at which the contents were last set
-   */
-  void accept2(String contents, int modificationTime);
+  void accept(String contents, int modificationTime);
 }
 
 /**
diff --git a/pkg/analyzer/lib/src/generated/source_io.dart b/pkg/analyzer/lib/src/generated/source_io.dart
index 0068239..ed1ae3b 100644
--- a/pkg/analyzer/lib/src/generated/source_io.dart
+++ b/pkg/analyzer/lib/src/generated/source_io.dart
@@ -108,7 +108,7 @@
 
   bool operator ==(Object object) => object != null && this.runtimeType == object.runtimeType && _file == (object as FileBasedSource)._file;
 
-  bool exists() => _contentCache.getContents(this) != null || (_file.exists() && !_file.isDirectory());
+  bool exists() => _contentCache.getContents(this) != null || _file.isFile();
 
   void getContents(Source_ContentReceiver receiver) {
     //
@@ -116,7 +116,7 @@
     //
     String contents = _contentCache.getContents(this);
     if (contents != null) {
-      receiver.accept2(contents, _contentCache.getModificationStamp(this));
+      receiver.accept(contents, _contentCache.getModificationStamp(this));
       return;
     }
     //
@@ -179,7 +179,7 @@
   void getContentsFromFile(Source_ContentReceiver receiver) {
     {
     }
-    receiver.accept2(file.readAsStringSync(), file.lastModified());
+    receiver.accept(file.readAsStringSync(), file.lastModified());
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/services/formatter_impl.dart b/pkg/analyzer/lib/src/services/formatter_impl.dart
index 1693dd6..0edd439 100644
--- a/pkg/analyzer/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer/lib/src/services/formatter_impl.dart
@@ -7,7 +7,6 @@
 import 'dart:math';
 
 import 'package:analyzer/analyzer.dart';
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
 import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -171,7 +170,7 @@
   }
 
   Token tokenize(String source) {
-    var reader = new CharSequenceReader(new CharSequence(source));
+    var reader = new CharSequenceReader(source);
     var scanner = new Scanner(null, reader, this);
     var token = scanner.tokenize();
     lineInfo = new LineInfo(scanner.lineStarts);
@@ -363,6 +362,9 @@
   /// addded to the indent level).
   bool allowLineLeadingSpaces;
 
+  /// A flag to specify whether zero-length spaces should be emmitted.
+  bool emitEmptySpaces = false;
+
   /// Used for matching EOL comments
   final twoSlashes = new RegExp(r'//[^/]');
 
@@ -412,7 +414,9 @@
 
   visitArgumentList(ArgumentList node) {
     token(node.leftParenthesis);
+    breakableNonSpace();
     visitCommaSeparatedNodes(node.arguments);
+    breakableNonSpace();
     token(node.rightParenthesis);
   }
 
@@ -453,10 +457,13 @@
   visitBlock(Block node) {
     token(node.leftBracket);
     indent();
-    visitNodes(node.statements, precededBy: newlines, separatedBy: newlines);
-    unindent();
-    newlines();
-    token(node.rightBracket);
+    if (!node.statements.isEmpty) {
+      visitNodes(node.statements, precededBy: newlines, separatedBy: newlines);
+      newlines();
+    } else {
+      preserveLeadingNewlines();
+    }
+    token(node.rightBracket, precededBy: unindent);
   }
 
   visitBlockFunctionBody(BlockFunctionBody node) {
@@ -524,10 +531,13 @@
     });
     token(node.leftBracket);
     indent();
-    visitNodes(node.members, precededBy: newlines, separatedBy: newlines);
-    unindent();
-    newlines();
-    token(node.rightBracket);
+    if (!node.members.isEmpty) {
+      visitNodes(node.members, precededBy: newlines, separatedBy: newlines);
+      newlines();
+    } else {
+      preserveLeadingNewlines();
+    }
+    token(node.rightBracket, precededBy: unindent);
   }
 
   visitClassTypeAlias(ClassTypeAlias node) {
@@ -622,7 +632,11 @@
   }
 
   visitConstructorInitializers(ConstructorDeclaration node) {
-    newlines();
+    if (node.initializers.length > 1) {
+      newlines();
+    } else {
+      preserveLeadingNewlines();
+    }
     indent(2);
     token(node.separator /* : */);
     space();
@@ -932,7 +946,7 @@
 
   visitInstanceCreationExpression(InstanceCreationExpression node) {
     token(node.keyword);
-    space();
+    nonBreakingSpace();
     visit(node.constructorName);
     visit(node.argumentList);
   }
@@ -994,8 +1008,7 @@
     indent();
     visitCommaSeparatedNodes(node.elements /*, followedBy: breakableSpace*/);
     optionalTrailingComma(node.rightBracket);
-    unindent();
-    token(node.rightBracket);
+    token(node.rightBracket, precededBy: unindent);
   }
 
   visitMapLiteral(MapLiteral node) {
@@ -1218,8 +1231,8 @@
     indent();
     newlines();
     visitNodes(node.members, separatedBy: newlines, followedBy: newlines);
-    unindent();
-    token(node.rightBracket);
+    token(node.rightBracket, precededBy: unindent);
+
   }
 
   visitSymbolLiteral(SymbolLiteral node) {
@@ -1442,8 +1455,8 @@
     preserveNewlines = true;
   }
 
-  token(Token token, {precededBy(), followedBy(),
-      printToken(tok), int minNewlines: 0}) {
+  token(Token token, {precededBy(), followedBy(), printToken(tok),
+      int minNewlines: 0}) {
     if (token != null) {
       if (needsNewline) {
         minNewlines = max(1, minNewlines);
@@ -1469,12 +1482,13 @@
   }
 
   emitSpaces() {
-    if (leadingSpaces > 0) {
+    if (leadingSpaces > 0 || emitEmptySpaces) {
       if (allowLineLeadingSpaces || !writer.currentLine.isWhitespace()) {
         writer.spaces(leadingSpaces, breakWeight: currentBreakWeight);
       }
       leadingSpaces = 0;
       allowLineLeadingSpaces = false;
+      emitEmptySpaces = false;
       currentBreakWeight = DEFAULT_SPACE_WEIGHT;
     }
   }
@@ -1493,6 +1507,12 @@
     }
   }
 
+  /// Emit a breakable 'non' (zero-length) space
+  breakableNonSpace() {
+    space(n: 0);
+    emitEmptySpaces = true;
+  }
+
   /// Emit a non-breakable space.
   nonBreakingSpace() {
     space(breakWeight: UNBREAKABLE_SPACE_WEIGHT);
@@ -1512,7 +1532,7 @@
   append(String string) {
     if (string != null && !string.isEmpty) {
       emitSpaces();
-      writer.print(string);
+      writer.write(string);
     }
   }
 
@@ -1538,8 +1558,7 @@
       newlines();
       visit(statement);
       newlines();
-      unindent();
-      token(CLOSE_CURLY);
+      token(CLOSE_CURLY, precededBy: unindent);
     } else {
       visit(statement);
     }
@@ -1566,6 +1585,7 @@
       lines = max(min, countNewlinesBetween(previousToken, currentToken));
       preserveNewlines = false;
     }
+
     emitNewlines(lines);
 
     previousToken =
diff --git a/pkg/analyzer/lib/src/services/runtime/coverage/coverage_impl.dart b/pkg/analyzer/lib/src/services/runtime/coverage/coverage_impl.dart
index 8e2fb90..bc1568a 100644
--- a/pkg/analyzer/lib/src/services/runtime/coverage/coverage_impl.dart
+++ b/pkg/analyzer/lib/src/services/runtime/coverage/coverage_impl.dart
@@ -11,7 +11,6 @@
 
 import 'package:path/path.dart' as pathos;
 
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
 import 'package:analyzer/src/generated/scanner.dart' show CharSequenceReader, Scanner;
 import 'package:analyzer/src/generated/parser.dart' show Parser;
 import 'package:analyzer/src/generated/ast.dart';
@@ -246,7 +245,7 @@
     var source = null;
     var errorListener = new RecordingErrorListener();
     var parser = new Parser(source, errorListener);
-    var reader = new CharSequenceReader(new CharSequence(code));
+    var reader = new CharSequenceReader(code);
     var scanner = new Scanner(null, reader, errorListener);
     var token = scanner.tokenize();
     return parser.parseCompilationUnit(token);
diff --git a/pkg/analyzer/lib/src/services/writer.dart b/pkg/analyzer/lib/src/services/writer.dart
index 78b837d..08cde1f 100644
--- a/pkg/analyzer/lib/src/services/writer.dart
+++ b/pkg/analyzer/lib/src/services/writer.dart
@@ -8,16 +8,16 @@
 
 class Line {
 
-  final tokens = <LineToken>[];
+  final List<LineToken> tokens = <LineToken>[];
   final bool useTabs;
   final int spacesPerIndent;
-  final int indent;
+  final int indentLevel;
   final LinePrinter printer;
 
-  Line({this.indent: 0, this.useTabs: false, this.spacesPerIndent: 2,
+  Line({this.indentLevel: 0, this.useTabs: false, this.spacesPerIndent: 2,
       this.printer: const SimpleLinePrinter()}) {
-    if (indent > 0) {
-      _indent(indent);
+    if (indentLevel > 0) {
+      indent(indentLevel);
     }
   }
 
@@ -26,19 +26,20 @@
   }
 
   void addSpaces(int n, {breakWeight: DEFAULT_SPACE_WEIGHT}) {
-    if (n > 0) {
-      tokens.add(new SpaceToken(n, breakWeight: breakWeight));
-    }
+    tokens.add(new SpaceToken(n, breakWeight: breakWeight));
   }
 
   void addToken(LineToken token) {
     tokens.add(token);
   }
 
+  bool isEmpty() => tokens.isEmpty;
+
   bool isWhitespace() => tokens.every((tok) => tok is SpaceToken);
 
-  void _indent(int n) {
-    tokens.add(useTabs ? new TabToken(n) : new SpaceToken(n * spacesPerIndent));
+  void indent(int n) {
+    tokens.insert(0,
+        useTabs ? new TabToken(n) : new SpaceToken(n * spacesPerIndent));
   }
 
   String toString() => printer.printLine(this);
@@ -79,7 +80,7 @@
     var chunks = breakLine(line);
     for (var i = 0; i < chunks.length; ++i) {
       if (i > 0) {
-        buf.write(indent(chunks[i], line.indent));
+        buf.write(indent(chunks[i], line.indentLevel));
       } else {
         buf.write(chunks[i]);
       }
@@ -309,7 +310,7 @@
     } else {
       linePrinter = new SimpleLinePrinter();
     }
-    currentLine = new Line(indent: indentCount, printer: linePrinter);
+    currentLine = newLine();
   }
 
   LineToken get lastToken => _lastToken;
@@ -321,6 +322,10 @@
 
   void indent() {
     ++indentCount;
+    // Rather than fiddle with deletions/insertions just start fresh
+    if (currentLine.isWhitespace()) {
+      currentLine = newLine();
+    }
   }
 
   void newline() {
@@ -329,7 +334,7 @@
     }
     _addToken(new NewlineToken(this.lineSeparator));
     buffer.write(currentLine.toString());
-    currentLine = new Line(indent: indentCount, printer: linePrinter);
+    currentLine = newLine();
   }
 
   void newlines(int num) {
@@ -338,12 +343,12 @@
     }
   }
 
-  void print(x) {
+  void write(x) {
     _addToken(new LineToken(x));
   }
 
-  void println(String s) {
-    print(s);
+  void writeln(String s) {
+    write(s);
     newline();
   }
 
@@ -357,8 +362,14 @@
 
   void unindent() {
     --indentCount;
+    // Rather than fiddle with deletions/insertions just start fresh
+    if (currentLine.isWhitespace()) {
+      currentLine = newLine();
+    }
   }
 
+  Line newLine() => new Line(indentLevel: indentCount, printer: linePrinter);
+
   String toString() {
     var source = new StringBuffer(buffer.toString());
     if (!currentLine.isWhitespace()) {
diff --git a/pkg/analyzer/lib/src/string_source.dart b/pkg/analyzer/lib/src/string_source.dart
index ab21809..7123bb4 100644
--- a/pkg/analyzer/lib/src/string_source.dart
+++ b/pkg/analyzer/lib/src/string_source.dart
@@ -26,7 +26,7 @@
   bool exists() => true;
 
   void getContents(Source_ContentReceiver receiver) =>
-      receiver.accept2(_contents, modificationStamp);
+      receiver.accept(_contents, modificationStamp);
 
   String get encoding => throw new UnsupportedError("StringSource doesn't support "
       "encoding.");
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index d0f4cb2..fb76d5a 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.11.10
+version: 0.12.0
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 122c5a7..68e4cba 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4494,7 +4494,7 @@
     //
     // Scan the source.
     //
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+    Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
     Token tokenStream = scanner.tokenize();
     //
     // Parse the source.
@@ -4544,7 +4544,7 @@
     //
     // Scan the source.
     //
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+    Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
     Token tokenStream = scanner.tokenize();
     //
     // Parse the source.
@@ -7403,7 +7403,7 @@
    */
   static CompilationUnit parseCompilationUnit(String source, List<ErrorCode> errorCodes) {
     GatheringErrorListener listener = new GatheringErrorListener();
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+    Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
     listener.setLineInfo(new TestSource(), scanner.lineStarts);
     Token token = scanner.tokenize();
     Parser parser = new Parser(null, listener);
@@ -7424,7 +7424,7 @@
    */
   static Expression parseExpression(String source, List<ErrorCode> errorCodes) {
     GatheringErrorListener listener = new GatheringErrorListener();
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+    Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
     listener.setLineInfo(new TestSource(), scanner.lineStarts);
     Token token = scanner.tokenize();
     Parser parser = new Parser(null, listener);
@@ -7445,7 +7445,7 @@
    */
   static Statement parseStatement(String source, List<ErrorCode> errorCodes) {
     GatheringErrorListener listener = new GatheringErrorListener();
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+    Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
     listener.setLineInfo(new TestSource(), scanner.lineStarts);
     Token token = scanner.tokenize();
     Parser parser = new Parser(null, listener);
@@ -7468,7 +7468,7 @@
    */
   static List<Statement> parseStatements(String source, int expectedCount, List<ErrorCode> errorCodes) {
     GatheringErrorListener listener = new GatheringErrorListener();
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+    Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
     listener.setLineInfo(new TestSource(), scanner.lineStarts);
     Token token = scanner.tokenize();
     Parser parser = new Parser(null, listener);
@@ -7498,7 +7498,7 @@
     //
     // Scan the source.
     //
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+    Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
     Token tokenStream = scanner.tokenize();
     listener.setLineInfo(new TestSource(), scanner.lineStarts);
     //
@@ -9431,7 +9431,7 @@
     // Parse the original contents.
     //
     GatheringErrorListener originalListener = new GatheringErrorListener();
-    Scanner originalScanner = new Scanner(source, new CharSequenceReader(new CharSequence(originalContents)), originalListener);
+    Scanner originalScanner = new Scanner(source, new CharSequenceReader(originalContents), originalListener);
     Token originalTokens = originalScanner.tokenize();
     JUnitTestCase.assertNotNull(originalTokens);
     Parser originalParser = new Parser(source, originalListener);
@@ -9441,7 +9441,7 @@
     // Parse the modified contents.
     //
     GatheringErrorListener modifiedListener = new GatheringErrorListener();
-    Scanner modifiedScanner = new Scanner(source, new CharSequenceReader(new CharSequence(modifiedContents)), modifiedListener);
+    Scanner modifiedScanner = new Scanner(source, new CharSequenceReader(modifiedContents), modifiedListener);
     Token modifiedTokens = modifiedScanner.tokenize();
     JUnitTestCase.assertNotNull(modifiedTokens);
     Parser modifiedParser = new Parser(source, modifiedListener);
@@ -9451,7 +9451,7 @@
     // Incrementally parse the modified contents.
     //
     GatheringErrorListener incrementalListener = new GatheringErrorListener();
-    IncrementalScanner incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(new CharSequence(modifiedContents)), incrementalListener);
+    IncrementalScanner incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(modifiedContents), incrementalListener);
     Token incrementalTokens = incrementalScanner.rescan(originalTokens, replaceStart, removed.length, added.length);
     JUnitTestCase.assertNotNull(incrementalTokens);
     IncrementalParser incrementalParser = new IncrementalParser(source, incrementalScanner.tokenMap, incrementalListener);
@@ -11645,7 +11645,7 @@
   'parseCompilationUnit_0': new MethodTrampoline(0, (Parser target) => target.parseCompilationUnit2()),
   'parseConditionalExpression_0': new MethodTrampoline(0, (Parser target) => target.parseConditionalExpression()),
   'parseConstructorName_0': new MethodTrampoline(0, (Parser target) => target.parseConstructorName()),
-  'parseExpression_0': new MethodTrampoline(0, (Parser target) => target.parseExpression4()),
+  'parseExpression_0': new MethodTrampoline(0, (Parser target) => target.parseExpression2()),
   'parseExpressionWithoutCascade_0': new MethodTrampoline(0, (Parser target) => target.parseExpressionWithoutCascade()),
   'parseExtendsClause_0': new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()),
   'parseFormalParameterList_0': new MethodTrampoline(0, (Parser target) => target.parseFormalParameterList()),
@@ -11782,8 +11782,8 @@
   'peek_0': new MethodTrampoline(0, (Parser target) => target.peek()),
   'peek_1': new MethodTrampoline(1, (Parser target, arg0) => target.peek2(arg0)),
   'reportError_1': new MethodTrampoline(1, (Parser target, arg0) => target.reportError(arg0)),
-  'reportError_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target.reportError11(arg0, arg1, arg2)),
-  'reportError_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target.reportError12(arg0, arg1)),
+  'reportError_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target.reportError12(arg0, arg1, arg2)),
+  'reportError_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target.reportError13(arg0, arg1)),
   'skipBlock_0': new MethodTrampoline(0, (Parser target) => target.skipBlock()),
   'skipFinalConstVarOrType_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipFinalConstVarOrType(arg0)),
   'skipFormalParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target.skipFormalParameterList(arg0)),
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 065a1ac..878187a 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -6798,6 +6798,16 @@
     assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
   }
 
+  void test_undefinedGetter_void() {
+    Source source = addSource(EngineTestCase.createSource([
+        "class T {",
+        "  void m() {}",
+        "}",
+        "f(T e) { return e.m().f; }"]));
+    resolve(source);
+    assertErrors(source, [StaticTypeWarningCode.UNDEFINED_GETTER]);
+  }
+
   void test_undefinedMethod() {
     Source source = addSource(EngineTestCase.createSource(["class A {", "  void m() {", "    n();", "  }", "}"]));
     resolve(source);
@@ -6894,6 +6904,16 @@
     assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
   }
 
+  void test_undefinedSetter_void() {
+    Source source = addSource(EngineTestCase.createSource([
+        "class T {",
+        "  void m() {}",
+        "}",
+        "f(T e) { e.m().f = 0; }"]));
+    resolve(source);
+    assertErrors(source, [StaticTypeWarningCode.UNDEFINED_SETTER]);
+  }
+
   void test_undefinedSuperMethod() {
     Source source = addSource(EngineTestCase.createSource([
         "class A {}",
@@ -7317,6 +7337,10 @@
         final __test = new StaticTypeWarningCodeTest();
         runJUnitTest(__test, __test.test_undefinedGetter_static);
       });
+      _ut.test('test_undefinedGetter_void', () {
+        final __test = new StaticTypeWarningCodeTest();
+        runJUnitTest(__test, __test.test_undefinedGetter_void);
+      });
       _ut.test('test_undefinedMethod', () {
         final __test = new StaticTypeWarningCodeTest();
         runJUnitTest(__test, __test.test_undefinedMethod);
@@ -7365,6 +7389,10 @@
         final __test = new StaticTypeWarningCodeTest();
         runJUnitTest(__test, __test.test_undefinedSetter_static);
       });
+      _ut.test('test_undefinedSetter_void', () {
+        final __test = new StaticTypeWarningCodeTest();
+        runJUnitTest(__test, __test.test_undefinedSetter_void);
+      });
       _ut.test('test_undefinedSuperMethod', () {
         final __test = new StaticTypeWarningCodeTest();
         runJUnitTest(__test, __test.test_undefinedSuperMethod);
@@ -7416,20 +7444,6 @@
     verify([source]);
   }
 
-  void fail_missingReturn_function() {
-    Source source = addSource(EngineTestCase.createSource(["int f() {}"]));
-    resolve(source);
-    assertErrors(source, [HintCode.MISSING_RETURN]);
-    verify([source]);
-  }
-
-  void fail_missingReturn_method() {
-    Source source = addSource(EngineTestCase.createSource(["class A {", "  int m() {}", "}"]));
-    resolve(source);
-    assertErrors(source, [HintCode.MISSING_RETURN]);
-    verify([source]);
-  }
-
   void fail_overriddingPrivateMember_getter() {
     Source source = addSource(EngineTestCase.createSource([
         "import 'lib1.dart';",
@@ -7989,6 +8003,20 @@
     verify([source]);
   }
 
+  void test_missingReturn_function() {
+    Source source = addSource(EngineTestCase.createSource(["int f() {}"]));
+    resolve(source);
+    assertErrors(source, [HintCode.MISSING_RETURN]);
+    verify([source]);
+  }
+
+  void test_missingReturn_method() {
+    Source source = addSource(EngineTestCase.createSource(["class A {", "  int m() {}", "}"]));
+    resolve(source);
+    assertErrors(source, [HintCode.MISSING_RETURN]);
+    verify([source]);
+  }
+
   void test_typeCheck_type_is_Null() {
     Source source = addSource(EngineTestCase.createSource(["m(i) {", "  bool b = i is Null;", "}"]));
     resolve(source);
@@ -8235,6 +8263,86 @@
     verify([source, source2]);
   }
 
+  void test_useOfVoidResult_assignmentExpression_function() {
+    Source source = addSource(EngineTestCase.createSource([
+        "void f() {}",
+        "class A {",
+        "  n() {",
+        "    var a;",
+        "    a = f();",
+        "  }",
+        "}"]));
+    resolve(source);
+    assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+    verify([source]);
+  }
+
+  void test_useOfVoidResult_assignmentExpression_method() {
+    Source source = addSource(EngineTestCase.createSource([
+        "class A {",
+        "  void m() {}",
+        "  n() {",
+        "    var a;",
+        "    a = m();",
+        "  }",
+        "}"]));
+    resolve(source);
+    assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+    verify([source]);
+  }
+
+  void test_useOfVoidResult_inForLoop() {
+    Source source = addSource(EngineTestCase.createSource([
+        "class A {",
+        "  void m() {}",
+        "  n() {",
+        "    for(var a = m();;) {}",
+        "  }",
+        "}"]));
+    resolve(source);
+    assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+    verify([source]);
+  }
+
+  void test_useOfVoidResult_variableDeclaration_function() {
+    Source source = addSource(EngineTestCase.createSource([
+        "void f() {}",
+        "class A {",
+        "  n() {",
+        "    var a = f();",
+        "  }",
+        "}"]));
+    resolve(source);
+    assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+    verify([source]);
+  }
+
+  void test_useOfVoidResult_variableDeclaration_method() {
+    Source source = addSource(EngineTestCase.createSource([
+        "class A {",
+        "  void m() {}",
+        "  n() {",
+        "    var a = m();",
+        "  }",
+        "}"]));
+    resolve(source);
+    assertErrors(source, [HintCode.USE_OF_VOID_RESULT]);
+    verify([source]);
+  }
+
+  void test_useOfVoidResult_variableDeclaration_method2() {
+    Source source = addSource(EngineTestCase.createSource([
+        "class A {",
+        "  void m() {}",
+        "  n() {",
+        "    var a = m(), b = m();",
+        "  }",
+        "}"]));
+    resolve(source);
+    assertErrors(source, [HintCode.USE_OF_VOID_RESULT, HintCode.USE_OF_VOID_RESULT]);
+    verify([source]);
+  }
+
   static dartSuite() {
     _ut.group('HintCodeTest', () {
       _ut.test('test_deadCode_deadBlock_conditionalElse', () {
@@ -8425,6 +8533,14 @@
         final __test = new HintCodeTest();
         runJUnitTest(__test, __test.test_isNotDouble);
       });
+      _ut.test('test_missingReturn_function', () {
+        final __test = new HintCodeTest();
+        runJUnitTest(__test, __test.test_missingReturn_function);
+      });
+      _ut.test('test_missingReturn_method', () {
+        final __test = new HintCodeTest();
+        runJUnitTest(__test, __test.test_missingReturn_method);
+      });
       _ut.test('test_typeCheck_type_is_Null', () {
         final __test = new HintCodeTest();
         runJUnitTest(__test, __test.test_typeCheck_type_is_Null);
@@ -8529,6 +8645,30 @@
         final __test = new HintCodeTest();
         runJUnitTest(__test, __test.test_unusedImport_show);
       });
+      _ut.test('test_useOfVoidResult_assignmentExpression_function', () {
+        final __test = new HintCodeTest();
+        runJUnitTest(__test, __test.test_useOfVoidResult_assignmentExpression_function);
+      });
+      _ut.test('test_useOfVoidResult_assignmentExpression_method', () {
+        final __test = new HintCodeTest();
+        runJUnitTest(__test, __test.test_useOfVoidResult_assignmentExpression_method);
+      });
+      _ut.test('test_useOfVoidResult_inForLoop', () {
+        final __test = new HintCodeTest();
+        runJUnitTest(__test, __test.test_useOfVoidResult_inForLoop);
+      });
+      _ut.test('test_useOfVoidResult_variableDeclaration_function', () {
+        final __test = new HintCodeTest();
+        runJUnitTest(__test, __test.test_useOfVoidResult_variableDeclaration_function);
+      });
+      _ut.test('test_useOfVoidResult_variableDeclaration_method', () {
+        final __test = new HintCodeTest();
+        runJUnitTest(__test, __test.test_useOfVoidResult_variableDeclaration_method);
+      });
+      _ut.test('test_useOfVoidResult_variableDeclaration_method2', () {
+        final __test = new HintCodeTest();
+        runJUnitTest(__test, __test.test_useOfVoidResult_variableDeclaration_method2);
+      });
     });
   }
 }
@@ -21694,6 +21834,26 @@
     verify([source]);
   }
 
+  void test_useOfVoidResult_implicitReturnValue() {
+    Source source = addSource(EngineTestCase.createSource([
+        "f() {}",
+        "class A {",
+        "  n() {",
+        "    var a = f();",
+        "  }",
+        "}"]));
+    resolve(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
+  void test_useOfVoidResult_nonVoidReturnValue() {
+    Source source = addSource(EngineTestCase.createSource(["int f() => 1;", "g() {", "  var a = f();", "}"]));
+    resolve(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   static dartSuite() {
     _ut.group('NonHintCodeTest', () {
       _ut.test('test_deadCode_deadBlock_conditionalElse_debugConst', () {
@@ -21876,6 +22036,14 @@
         final __test = new NonHintCodeTest();
         runJUnitTest(__test, __test.test_unusedImport_prefix_topLevelFunction);
       });
+      _ut.test('test_useOfVoidResult_implicitReturnValue', () {
+        final __test = new NonHintCodeTest();
+        runJUnitTest(__test, __test.test_useOfVoidResult_implicitReturnValue);
+      });
+      _ut.test('test_useOfVoidResult_nonVoidReturnValue', () {
+        final __test = new NonHintCodeTest();
+        runJUnitTest(__test, __test.test_useOfVoidResult_nonVoidReturnValue);
+      });
     });
   }
 }
diff --git a/pkg/analyzer/test/generated/scanner_test.dart b/pkg/analyzer/test/generated/scanner_test.dart
index 4923566..6413ba9 100644
--- a/pkg/analyzer/test/generated/scanner_test.dart
+++ b/pkg/analyzer/test/generated/scanner_test.dart
@@ -70,18 +70,18 @@
 
 class CharSequenceReaderTest extends JUnitTestCase {
   void test_advance() {
-    CharSequenceReader reader = new CharSequenceReader(new CharSequence("x"));
+    CharSequenceReader reader = new CharSequenceReader("x");
     JUnitTestCase.assertEquals(0x78, reader.advance());
     JUnitTestCase.assertEquals(-1, reader.advance());
     JUnitTestCase.assertEquals(-1, reader.advance());
   }
 
   void test_creation() {
-    JUnitTestCase.assertNotNull(new CharSequenceReader(new CharSequence("x")));
+    JUnitTestCase.assertNotNull(new CharSequenceReader("x"));
   }
 
   void test_getOffset() {
-    CharSequenceReader reader = new CharSequenceReader(new CharSequence("x"));
+    CharSequenceReader reader = new CharSequenceReader("x");
     JUnitTestCase.assertEquals(-1, reader.offset);
     reader.advance();
     JUnitTestCase.assertEquals(0, reader.offset);
@@ -90,14 +90,14 @@
   }
 
   void test_getString() {
-    CharSequenceReader reader = new CharSequenceReader(new CharSequence("xyzzy"));
+    CharSequenceReader reader = new CharSequenceReader("xyzzy");
     reader.offset = 3;
     JUnitTestCase.assertEquals("yzz", reader.getString(1, 0));
     JUnitTestCase.assertEquals("zzy", reader.getString(2, 1));
   }
 
   void test_peek() {
-    CharSequenceReader reader = new CharSequenceReader(new CharSequence("xy"));
+    CharSequenceReader reader = new CharSequenceReader("xy");
     JUnitTestCase.assertEquals(0x78, reader.peek());
     JUnitTestCase.assertEquals(0x78, reader.peek());
     reader.advance();
@@ -109,7 +109,7 @@
   }
 
   void test_setOffset() {
-    CharSequenceReader reader = new CharSequenceReader(new CharSequence("xyz"));
+    CharSequenceReader reader = new CharSequenceReader("xyz");
     reader.offset = 2;
     JUnitTestCase.assertEquals(2, reader.offset);
   }
@@ -375,7 +375,7 @@
   }
 
   void test_comment_disabled_multi() {
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence("/* comment */ ")), AnalysisErrorListener.NULL_LISTENER);
+    Scanner scanner = new Scanner(null, new CharSequenceReader("/* comment */ "), AnalysisErrorListener.NULL_LISTENER);
     scanner.preserveComments = false;
     Token token = scanner.tokenize();
     JUnitTestCase.assertNotNull(token);
@@ -838,7 +838,7 @@
   void test_setSourceStart() {
     int offsetDelta = 42;
     GatheringErrorListener listener = new GatheringErrorListener();
-    Scanner scanner = new Scanner(null, new SubSequenceReader(new CharSequence("a"), offsetDelta), listener);
+    Scanner scanner = new Scanner(null, new SubSequenceReader("a", offsetDelta), listener);
     scanner.setSourceStart(3, 9);
     scanner.tokenize();
     List<int> lineStarts = scanner.lineStarts;
@@ -1211,7 +1211,7 @@
   }
 
   Token scan2(String source, GatheringErrorListener listener) {
-    Scanner scanner = new Scanner(null, new CharSequenceReader(new CharSequence(source)), listener);
+    Scanner scanner = new Scanner(null, new CharSequenceReader(source), listener);
     Token result = scanner.tokenize();
     listener.setLineInfo(new TestSource(), scanner.lineStarts);
     return result;
@@ -2250,21 +2250,21 @@
     // Scan the original contents.
     //
     GatheringErrorListener originalListener = new GatheringErrorListener();
-    Scanner originalScanner = new Scanner(source, new CharSequenceReader(new CharSequence(originalContents)), originalListener);
+    Scanner originalScanner = new Scanner(source, new CharSequenceReader(originalContents), originalListener);
     _originalTokens = originalScanner.tokenize();
     JUnitTestCase.assertNotNull(_originalTokens);
     //
     // Scan the modified contents.
     //
     GatheringErrorListener modifiedListener = new GatheringErrorListener();
-    Scanner modifiedScanner = new Scanner(source, new CharSequenceReader(new CharSequence(modifiedContents)), modifiedListener);
+    Scanner modifiedScanner = new Scanner(source, new CharSequenceReader(modifiedContents), modifiedListener);
     Token modifiedTokens = modifiedScanner.tokenize();
     JUnitTestCase.assertNotNull(modifiedTokens);
     //
     // Incrementally scan the modified contents.
     //
     GatheringErrorListener incrementalListener = new GatheringErrorListener();
-    _incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(new CharSequence(modifiedContents)), incrementalListener);
+    _incrementalScanner = new IncrementalScanner(source, new CharSequenceReader(modifiedContents), incrementalListener);
     _incrementalTokens = _incrementalScanner.rescan(_originalTokens, replaceStart, removed.length, added.length);
     //
     // Validate that the results of the incremental scan are the same as the full scan of the
diff --git a/pkg/analyzer/test/services/data/cu_tests.data b/pkg/analyzer/test/services/data/cu_tests.data
index 9091620..65b6c42 100644
--- a/pkg/analyzer/test/services/data/cu_tests.data
+++ b/pkg/analyzer/test/services/data/cu_tests.data
@@ -200,4 +200,50 @@
   List<double> tangentImpulses = new List<double>(Settings.MAX_MANIFOLD_POINTS);
 
   ContactImpulse();
+}
+>>> Empty class bodies may be on one line (or more)
+class A extends B { }
+<<<
+class A extends B {}
+>>>
+class A extends B {
+
+}
+<<<
+class A extends B {
+
+}
+>>> Single initializers can be on one line
+class Foo extends Bar {
+  final int b;
+  Foo(int a, this.b): super(a);
+}
+<<<
+class Foo extends Bar {
+  final int b;
+  Foo(int a, this.b): super(a);
+}
+>>> (or not)
+class Foo extends Bar {
+  final int b;
+  Foo(int a, this.b)
+      : super(a);
+}
+<<<
+class Foo extends Bar {
+  final int b;
+  Foo(int a, this.b)
+      : super(a);
+}
+>>> Multiple initializers are one per line
+class Foo extends Bar {
+  final int b;
+  Foo(int a, int b) : super(a), this.b = b == null ? 0 : b;
+}
+<<<
+class Foo extends Bar {
+  final int b;
+  Foo(int a, int b)
+      : super(a),
+        this.b = b == null ? 0 : b;
 }
\ No newline at end of file
diff --git a/pkg/analyzer/test/services/data/stmt_tests.data b/pkg/analyzer/test/services/data/stmt_tests.data
index 7557479..c50f2aa 100644
--- a/pkg/analyzer/test/services/data/stmt_tests.data
+++ b/pkg/analyzer/test/services/data/stmt_tests.data
@@ -44,7 +44,8 @@
 }
 <<<<
 blah() {
-  print('blah blah blah blah blah blah blah blah blah blah blah blah blah blah $foo');
+  print(
+      'blah blah blah blah blah blah blah blah blah blah blah blah blah blah $foo');
 }
 >>>
 assert(false);
@@ -98,3 +99,37 @@
       break;
   }
 }
+>>> dartbug.com/16383
+main() {
+  //foo
+}
+<<<
+main() {
+  //foo
+}
+>>> dartbug.com/16379
+var x = new XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX();
+<<<
+var x =
+    new XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX();
+>>>
+main() {
+  throw new FormatException("This is a long exception message that puts this over 80 columns.");
+}
+<<<
+main() {
+  throw new FormatException(
+      "This is a long exception message that puts this over 80 columns.");
+}
+>>> Empty method bodies may be on a single line (or more)
+void main() { }
+<<<
+void main() {}
+>>>
+void main() {
+
+}
+<<<
+void main() {
+
+}
diff --git a/pkg/analyzer/test/services/data/style_guide_tests.data b/pkg/analyzer/test/services/data/style_guide_tests.data
index d0b49ef..781516d 100644
--- a/pkg/analyzer/test/services/data/style_guide_tests.data
+++ b/pkg/analyzer/test/services/data/style_guide_tests.data
@@ -164,8 +164,7 @@
 }
 <<<
 getEmptyFn(a) {
-  return () {
-  };
+  return () {};
 }
 >>> DO format constructor initialization lists with each field on its own line.
 class MyClass {
diff --git a/pkg/analyzer/test/services/formatter_test.dart b/pkg/analyzer/test/services/formatter_test.dart
index 7703a68..f3557d7 100644
--- a/pkg/analyzer/test/services/formatter_test.dart
+++ b/pkg/analyzer/test/services/formatter_test.dart
@@ -7,7 +7,6 @@
 import 'package:path/path.dart';
 import 'package:unittest/unittest.dart';
 
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/services/formatter_impl.dart';
 import 'package:analyzer/src/services/writer.dart';
@@ -189,8 +188,7 @@
       expectCUFormatsTo(
           'library a; class B { }',
           'library a;\n'
-          'class B {\n'
-          '}\n'
+          'class B {}\n'
       );
     });
 
@@ -655,20 +653,6 @@
         );
     });
 
-    test('CU - constructor initializers', () {
-      expectCUFormatsTo(
-          'class A {\n'
-          '  int _a;\n'
-          '  A(a) : _a = a;\n'
-          '}\n',
-          'class A {\n'
-          '  int _a;\n'
-          '  A(a)\n'
-          '      : _a = a;\n'
-          '}\n'
-        );
-    });
-
     test('CU - constructor auto field inits', () {
       expectCUFormatsTo(
           'class A {\n'
@@ -953,8 +937,7 @@
         'abstract\n'
         'class\n'
         'A{}',
-        'abstract class A {\n'
-        '}\n'
+        'abstract class A {}\n'
       );
     });
 
@@ -1143,18 +1126,18 @@
   group('line', () {
 
     test('space', () {
-      var line = new Line(indent: 0);
+      var line = new Line(indentLevel: 0);
       line.addSpaces(2);
       expect(line.toString(), equals('  '));
     });
 
     test('initial indent', () {
-      var line = new Line(indent: 2);
+      var line = new Line(indentLevel: 2);
       expect(line.toString(), equals('    '));
     });
 
     test('initial indent (tabbed)', () {
-      var line = new Line(indent:1, useTabs: true);
+      var line = new Line(indentLevel:1, useTabs: true);
       expect(line.toString(), equals('\t'));
     });
 
@@ -1165,13 +1148,13 @@
     });
 
     test('addToken (2)', () {
-      var line = new Line(indent: 1);
+      var line = new Line(indentLevel: 1);
       line.addToken(new LineToken('foo'));
       expect(line.toString(), equals('  foo'));
     });
 
     test('isWhitespace', () {
-      var line = new Line(indent: 1);
+      var line = new Line(indentLevel: 1);
       expect(line.isWhitespace(), isTrue);
     });
 
@@ -1182,15 +1165,15 @@
 
     test('basic print', () {
       var writer = new SourceWriter();
-      writer.print('foo');
-      writer.print(' ');
-      writer.print('bar');
+      writer.write('foo');
+      writer.write(' ');
+      writer.write('bar');
       expect(writer.toString(), equals('foo bar'));
     });
 
     test('newline', () {
       var writer = new SourceWriter();
-      writer.print('foo');
+      writer.write('foo');
       writer.newline();
       expect(writer.toString(), equals('foo\n'));
     });
@@ -1203,13 +1186,13 @@
 
     test('basic print (with indents)', () {
       var writer = new SourceWriter();
-      writer.print('foo');
+      writer.write('foo');
       writer.indent();
       writer.newline();
-      writer.print('bar');
+      writer.write('bar');
       writer.unindent();
       writer.newline();
-      writer.print('baz');
+      writer.write('baz');
       expect(writer.toString(), equals('foo\n  bar\nbaz'));
     });
 
@@ -1400,7 +1383,7 @@
     new CodeFormatter(options).format(CodeKind.STATEMENT, src).source;
 
 Token tokenize(String str) {
-  var reader = new CharSequenceReader(new CharSequence(str));
+  var reader = new CharSequenceReader(str);
   return new Scanner(null, reader, null).tokenize();
 }
 
diff --git a/pkg/analyzer/test/services/test_utils.dart b/pkg/analyzer/test/services/test_utils.dart
index 65960a1..2a95fb3 100644
--- a/pkg/analyzer/test/services/test_utils.dart
+++ b/pkg/analyzer/test/services/test_utils.dart
@@ -6,7 +6,6 @@
 
 import 'package:unittest/unittest.dart';
 
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext, AnalysisContextImpl;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/error.dart';
@@ -198,7 +197,7 @@
 Statement parseStatement(String source, [List<ErrorCode> expectedErrorCodes]) {
 
   var listener = new _GatheringErrorListener();
-  var reader = new CharSequenceReader(new CharSequence(source));
+  var reader = new CharSequenceReader(source);
   var scanner = new Scanner(null, reader, listener);
   listener.setLineInfo(new _TestSource(), scanner.lineStarts);
 
diff --git a/pkg/barback/lib/src/asset_cascade.dart b/pkg/barback/lib/src/asset_cascade.dart
index 3454899..af0b90c 100644
--- a/pkg/barback/lib/src/asset_cascade.dart
+++ b/pkg/barback/lib/src/asset_cascade.dart
@@ -117,7 +117,7 @@
   /// It loads source assets within [package] using [provider].
   AssetCascade(this.graph, this.package) {
     _onDirtyPool.add(_onDirtyController.stream);
-    _addPhase(new Phase(this, []));
+    _addPhase(new Phase(this, [], package));
 
     // Keep track of logged errors so we can know that the build failed.
     onLog.listen((entry) {
@@ -308,4 +308,6 @@
       return future.then((_) => _process());
     });
   }
+
+  String toString() => "cascade for $package";
 }
diff --git a/pkg/barback/lib/src/asset_node.dart b/pkg/barback/lib/src/asset_node.dart
index a1af547..7ea442a 100644
--- a/pkg/barback/lib/src/asset_node.dart
+++ b/pkg/barback/lib/src/asset_node.dart
@@ -137,6 +137,8 @@
       : id = asset.id,
         _asset = asset,
         _state = AssetState.AVAILABLE;
+
+  String toString() => "$state asset $id";
 }
 
 /// The controller for an [AssetNode].
@@ -199,6 +201,8 @@
     node._asset = asset;
     node._stateChangeController.add(AssetState.AVAILABLE);
   }
+
+  String toString() => "controller for $node";
 }
 
 // TODO(nweiz): add an error state.
diff --git a/pkg/barback/lib/src/asset_set.dart b/pkg/barback/lib/src/asset_set.dart
index 08c2db9..b17db97 100644
--- a/pkg/barback/lib/src/asset_set.dart
+++ b/pkg/barback/lib/src/asset_set.dart
@@ -68,4 +68,6 @@
   void clear() {
     _assets.clear();
   }
+
+  String toString() => _assets.toString();
 }
diff --git a/pkg/barback/lib/src/group_runner.dart b/pkg/barback/lib/src/group_runner.dart
index 4718d18..d276796 100644
--- a/pkg/barback/lib/src/group_runner.dart
+++ b/pkg/barback/lib/src/group_runner.dart
@@ -13,10 +13,16 @@
 import 'stream_pool.dart';
 import 'transformer_group.dart';
 
-/// A class that process all of the phases in a single transformer group.
+/// A class that processes all of the phases in a single transformer group.
 ///
 /// A group takes many inputs, processes them, and emits many outputs.
 class GroupRunner {
+  /// The group this runner runs.
+  final TransformerGroup _group;
+
+  /// A string describing the location of [this] in the transformer graph.
+  final String _location;
+
   /// The phases defined by this group.
   final _phases = new List<Phase>();
 
@@ -46,10 +52,10 @@
   /// ensure that it does so.
   final _alreadyEmittedOutputs = new Set<AssetNode>();
 
-  GroupRunner(AssetCascade cascade, TransformerGroup group) {
-    var lastPhase = new Phase(cascade, group.phases.first);
+  GroupRunner(AssetCascade cascade, this._group, this._location) {
+    var lastPhase = new Phase(cascade, _group.phases.first, _location);
     _phases.add(lastPhase);
-    for (var phase in group.phases.skip(1)) {
+    for (var phase in _group.phases.skip(1)) {
       lastPhase = lastPhase.addPhase(phase);
       _phases.add(lastPhase);
     }
@@ -91,4 +97,6 @@
 
     return new Future.value(newOutputs);
   }
+
+  String toString() => "group in phase $_location for $_group";
 }
diff --git a/pkg/barback/lib/src/phase.dart b/pkg/barback/lib/src/phase.dart
index 2136a12..aa570bf 100644
--- a/pkg/barback/lib/src/phase.dart
+++ b/pkg/barback/lib/src/phase.dart
@@ -36,6 +36,12 @@
   /// The cascade that owns this phase.
   final AssetCascade cascade;
 
+  /// A string describing the location of [this] in the transformer graph.
+  final String _location;
+
+  /// The index of [this] in its parent cascade or group.
+  final int _index;
+
   /// The transformers that can access [inputs].
   ///
   /// Their outputs will be available to the next phase.
@@ -111,12 +117,15 @@
   // TODO(nweiz): Rather than passing the cascade and the phase everywhere,
   // create an interface that just exposes [getInput]. Emit errors via
   // [AssetNode]s.
-  Phase(this.cascade, Iterable transformers)
+  Phase(AssetCascade cascade, Iterable transformers, String location)
+      : this._(cascade, transformers, location, 0);
+
+  Phase._(this.cascade, Iterable transformers, this._location, this._index)
       : _transformers = transformers.where((op) => op is Transformer).toSet() {
     _onDirtyPool.add(_onDirtyController.stream);
 
     for (var group in transformers.where((op) => op is TransformerGroup)) {
-      var runner = new GroupRunner(cascade, group);
+      var runner = new GroupRunner(cascade, group, "$_location.$_index");
       _groups[group] = runner;
       _onDirtyPool.add(runner.onDirty);
       _onLogPool.add(runner.onLog);
@@ -148,7 +157,7 @@
     });
 
     _inputOrigins.add(node.origin);
-    var input = new PhaseInput(this, node, _transformers);
+    var input = new PhaseInput(this, node, _transformers, "$_location.$_index");
     _inputs[node.id] = input;
     input.input.whenRemoved(() {
       _inputOrigins.remove(node.origin);
@@ -205,7 +214,7 @@
     }
 
     for (var added in newGroups.difference(oldGroups)) {
-      var runner = new GroupRunner(cascade, added);
+      var runner = new GroupRunner(cascade, added, "$_location.$_index");
       _groups[added] = runner;
       _onDirtyPool.add(runner.onDirty);
       _onLogPool.add(runner.onLog);
@@ -224,7 +233,7 @@
   /// This may only be called on a phase with no phase following it.
   Phase addPhase(Iterable transformers) {
     assert(_next == null);
-    _next = new Phase(cascade, transformers);
+    _next = new Phase._(cascade, transformers, _location, _index + 1);
     for (var output in _outputs.values.toList()) {
       // Remove [output]'s listeners because now they should get the asset from
       // [_next], rather than this phase. Any transforms consuming [output] will
@@ -305,11 +314,13 @@
     if (_outputs.containsKey(asset.id)) {
       _outputs[asset.id].add(asset);
     } else {
-      _outputs[asset.id] = new PhaseOutput(this, asset);
+      _outputs[asset.id] = new PhaseOutput(this, asset, "$_location.$_index");
       _outputs[asset.id].onAsset.listen((output) {
         if (_next != null) _next.addInput(output);
       }, onDone: () => _outputs.remove(asset.id));
       if (_next != null) _next.addInput(_outputs[asset.id].output);
     }
   }
+
+  String toString() => "phase $_location.$_index";
 }
diff --git a/pkg/barback/lib/src/phase_input.dart b/pkg/barback/lib/src/phase_input.dart
index 13bc700..4937467 100644
--- a/pkg/barback/lib/src/phase_input.dart
+++ b/pkg/barback/lib/src/phase_input.dart
@@ -24,6 +24,9 @@
   /// The phase for which this is an input.
   final Phase _phase;
 
+  /// A string describing the location of [this] in the transformer graph.
+  final String _location;
+
   /// The transformers to (potentially) run against [input].
   final Set<Transformer> _transformers;
 
@@ -84,7 +87,8 @@
   Stream<LogEntry> get onLog => _onLogPool.stream;
   final _onLogPool = new StreamPool<LogEntry>.broadcast();
 
-  PhaseInput(this._phase, AssetNode input, Iterable<Transformer> transformers)
+  PhaseInput(this._phase, AssetNode input, Iterable<Transformer> transformers,
+      this._location)
       : _transformers = transformers.toSet(),
         _inputForwarder = new AssetForwarder(input) {
     _onDirtyPool.add(_onDirtyController.stream);
@@ -228,7 +232,8 @@
       // results.
       return transformer.isPrimary(input.asset).then((isPrimary) {
         if (!isPrimary) return;
-        var transform = new TransformNode(_phase, transformer, input);
+        var transform = new TransformNode(
+            _phase, transformer, input, _location);
         _transforms.add(transform);
         _onDirtyPool.add(transform.onDirty);
         _onLogPool.add(transform.onLog);
@@ -312,4 +317,6 @@
       return transform.apply();
     })).then((outputs) => unionAll(outputs));
   }
+
+  String toString() => "phase input in $_location for $input";
 }
diff --git a/pkg/barback/lib/src/phase_output.dart b/pkg/barback/lib/src/phase_output.dart
index 17a613f..50d39c3 100644
--- a/pkg/barback/lib/src/phase_output.dart
+++ b/pkg/barback/lib/src/phase_output.dart
@@ -28,6 +28,9 @@
   /// The phase for which this is an output.
   final Phase _phase;
 
+  /// A string describing the location of [this] in the transformer graph.
+  final String _location;
+
   /// The asset node for this output.
   AssetNode get output => _outputForwarder.node;
   AssetForwarder _outputForwarder;
@@ -53,7 +56,7 @@
         output.id);
   }
 
-  PhaseOutput(this._phase, AssetNode output)
+  PhaseOutput(this._phase, AssetNode output, this._location)
       : _outputForwarder = new AssetForwarder(output) {
     assert(!output.state.isRemoved);
     add(output);
@@ -109,4 +112,6 @@
       }
     });
   }
+
+  String toString() => "phase output in $_location for $output";
 }
diff --git a/pkg/barback/lib/src/transform_node.dart b/pkg/barback/lib/src/transform_node.dart
index 76b29bd..8a79b6c 100644
--- a/pkg/barback/lib/src/transform_node.dart
+++ b/pkg/barback/lib/src/transform_node.dart
@@ -33,6 +33,9 @@
   /// The node for the primary asset this transform depends on.
   final AssetNode primary;
 
+  /// A string describing the location of [this] in the transformer graph.
+  final String _location;
+
   /// The subscription to [primary]'s [AssetNode.onStateChange] stream.
   StreamSubscription _primarySubscription;
 
@@ -64,7 +67,7 @@
   Stream<LogEntry> get onLog => _onLogController.stream;
   final _onLogController = new StreamController<LogEntry>.broadcast(sync: true);
 
-  TransformNode(this.phase, this.transformer, this.primary) {
+  TransformNode(this.phase, this.transformer, this.primary, this._location) {
     _primarySubscription = primary.onStateChange.listen((state) {
       if (state.isRemoved) {
         remove();
@@ -219,4 +222,7 @@
     var entry = new LogEntry(info, asset, level, message, span);
     _onLogController.add(entry);
   }
+
+  String toString() =>
+    "transform node in $_location for $transformer on $primary";
 }
diff --git a/pkg/barback/lib/src/transformer_group.dart b/pkg/barback/lib/src/transformer_group.dart
index 49359c9..58ffd2a 100644
--- a/pkg/barback/lib/src/transformer_group.dart
+++ b/pkg/barback/lib/src/transformer_group.dart
@@ -25,4 +25,6 @@
 
   TransformerGroup(Iterable<Iterable> phases)
       : this.phases = phases.map((phase) => phase.toList()).toList();
+
+  String toString() => "group of $phases";
 }
diff --git a/pkg/custom_element/REVISION b/pkg/custom_element/REVISION
new file mode 100644
index 0000000..309f953
--- /dev/null
+++ b/pkg/custom_element/REVISION
@@ -0,0 +1,4 @@
+sources are from:
+
+https://github.com/Polymer/MutationObservers/commit/a8aa7f9cc35c3ebef152be42f87ec2677a87f55e
+https://github.com/dart-lang/CustomElements/commit/44178138302584392ab51515e2959d8ab925b155
diff --git a/pkg/custom_element/lib/custom-elements.debug.js b/pkg/custom_element/lib/custom-elements.debug.js
index fe98775..e3c53e0 100644
--- a/pkg/custom_element/lib/custom-elements.debug.js
+++ b/pkg/custom_element/lib/custom-elements.debug.js
@@ -56,6 +56,547 @@
   })();
 }
 
+(function(global) {
+
+  var registrationsTable = new WeakMap();
+
+  // We use setImmediate or postMessage for our future callback.
+  var setImmediate = window.msSetImmediate;
+
+  // Use post message to emulate setImmediate.
+  if (!setImmediate) {
+    var setImmediateQueue = [];
+    var sentinel = String(Math.random());
+    window.addEventListener('message', function(e) {
+      if (e.data === sentinel) {
+        var queue = setImmediateQueue;
+        setImmediateQueue = [];
+        queue.forEach(function(func) {
+          func();
+        });
+      }
+    });
+    setImmediate = function(func) {
+      setImmediateQueue.push(func);
+      window.postMessage(sentinel, '*');
+    };
+  }
+
+  // This is used to ensure that we never schedule 2 callas to setImmediate
+  var isScheduled = false;
+
+  // Keep track of observers that needs to be notified next time.
+  var scheduledObservers = [];
+
+  /**
+   * Schedules |dispatchCallback| to be called in the future.
+   * @param {MutationObserver} observer
+   */
+  function scheduleCallback(observer) {
+    scheduledObservers.push(observer);
+    if (!isScheduled) {
+      isScheduled = true;
+      setImmediate(dispatchCallbacks);
+    }
+  }
+
+  function wrapIfNeeded(node) {
+    return window.ShadowDOMPolyfill &&
+        window.ShadowDOMPolyfill.wrapIfNeeded(node) ||
+        node;
+  }
+
+  function dispatchCallbacks() {
+    // http://dom.spec.whatwg.org/#mutation-observers
+
+    isScheduled = false; // Used to allow a new setImmediate call above.
+
+    var observers = scheduledObservers;
+    scheduledObservers = [];
+    // Sort observers based on their creation UID (incremental).
+    observers.sort(function(o1, o2) {
+      return o1.uid_ - o2.uid_;
+    });
+
+    var anyNonEmpty = false;
+    observers.forEach(function(observer) {
+
+      // 2.1, 2.2
+      var queue = observer.takeRecords();
+      // 2.3. Remove all transient registered observers whose observer is mo.
+      removeTransientObserversFor(observer);
+
+      // 2.4
+      if (queue.length) {
+        observer.callback_(queue, observer);
+        anyNonEmpty = true;
+      }
+    });
+
+    // 3.
+    if (anyNonEmpty)
+      dispatchCallbacks();
+  }
+
+  function removeTransientObserversFor(observer) {
+    observer.nodes_.forEach(function(node) {
+      var registrations = registrationsTable.get(node);
+      if (!registrations)
+        return;
+      registrations.forEach(function(registration) {
+        if (registration.observer === observer)
+          registration.removeTransientObservers();
+      });
+    });
+  }
+
+  /**
+   * This function is used for the "For each registered observer observer (with
+   * observer's options as options) in target's list of registered observers,
+   * run these substeps:" and the "For each ancestor ancestor of target, and for
+   * each registered observer observer (with options options) in ancestor's list
+   * of registered observers, run these substeps:" part of the algorithms. The
+   * |options.subtree| is checked to ensure that the callback is called
+   * correctly.
+   *
+   * @param {Node} target
+   * @param {function(MutationObserverInit):MutationRecord} callback
+   */
+  function forEachAncestorAndObserverEnqueueRecord(target, callback) {
+    for (var node = target; node; node = node.parentNode) {
+      var registrations = registrationsTable.get(node);
+
+      if (registrations) {
+        for (var j = 0; j < registrations.length; j++) {
+          var registration = registrations[j];
+          var options = registration.options;
+
+          // Only target ignores subtree.
+          if (node !== target && !options.subtree)
+            continue;
+
+          var record = callback(options);
+          if (record)
+            registration.enqueue(record);
+        }
+      }
+    }
+  }
+
+  var uidCounter = 0;
+
+  /**
+   * The class that maps to the DOM MutationObserver interface.
+   * @param {Function} callback.
+   * @constructor
+   */
+  function JsMutationObserver(callback) {
+    this.callback_ = callback;
+    this.nodes_ = [];
+    this.records_ = [];
+    this.uid_ = ++uidCounter;
+  }
+
+  JsMutationObserver.prototype = {
+    observe: function(target, options) {
+      target = wrapIfNeeded(target);
+
+      // 1.1
+      if (!options.childList && !options.attributes && !options.characterData ||
+
+          // 1.2
+          options.attributeOldValue && !options.attributes ||
+
+          // 1.3
+          options.attributeFilter && options.attributeFilter.length &&
+              !options.attributes ||
+
+          // 1.4
+          options.characterDataOldValue && !options.characterData) {
+
+        throw new SyntaxError();
+      }
+
+      var registrations = registrationsTable.get(target);
+      if (!registrations)
+        registrationsTable.set(target, registrations = []);
+
+      // 2
+      // If target's list of registered observers already includes a registered
+      // observer associated with the context object, replace that registered
+      // observer's options with options.
+      var registration;
+      for (var i = 0; i < registrations.length; i++) {
+        if (registrations[i].observer === this) {
+          registration = registrations[i];
+          registration.removeListeners();
+          registration.options = options;
+          break;
+        }
+      }
+
+      // 3.
+      // Otherwise, add a new registered observer to target's list of registered
+      // observers with the context object as the observer and options as the
+      // options, and add target to context object's list of nodes on which it
+      // is registered.
+      if (!registration) {
+        registration = new Registration(this, target, options);
+        registrations.push(registration);
+        this.nodes_.push(target);
+      }
+
+      registration.addListeners();
+    },
+
+    disconnect: function() {
+      this.nodes_.forEach(function(node) {
+        var registrations = registrationsTable.get(node);
+        for (var i = 0; i < registrations.length; i++) {
+          var registration = registrations[i];
+          if (registration.observer === this) {
+            registration.removeListeners();
+            registrations.splice(i, 1);
+            // Each node can only have one registered observer associated with
+            // this observer.
+            break;
+          }
+        }
+      }, this);
+      this.records_ = [];
+    },
+
+    takeRecords: function() {
+      var copyOfRecords = this.records_;
+      this.records_ = [];
+      return copyOfRecords;
+    }
+  };
+
+  /**
+   * @param {string} type
+   * @param {Node} target
+   * @constructor
+   */
+  function MutationRecord(type, target) {
+    this.type = type;
+    this.target = target;
+    this.addedNodes = [];
+    this.removedNodes = [];
+    this.previousSibling = null;
+    this.nextSibling = null;
+    this.attributeName = null;
+    this.attributeNamespace = null;
+    this.oldValue = null;
+  }
+
+  function copyMutationRecord(original) {
+    var record = new MutationRecord(original.type, original.target);
+    record.addedNodes = original.addedNodes.slice();
+    record.removedNodes = original.removedNodes.slice();
+    record.previousSibling = original.previousSibling;
+    record.nextSibling = original.nextSibling;
+    record.attributeName = original.attributeName;
+    record.attributeNamespace = original.attributeNamespace;
+    record.oldValue = original.oldValue;
+    return record;
+  };
+
+  // We keep track of the two (possibly one) records used in a single mutation.
+  var currentRecord, recordWithOldValue;
+
+  /**
+   * Creates a record without |oldValue| and caches it as |currentRecord| for
+   * later use.
+   * @param {string} oldValue
+   * @return {MutationRecord}
+   */
+  function getRecord(type, target) {
+    return currentRecord = new MutationRecord(type, target);
+  }
+
+  /**
+   * Gets or creates a record with |oldValue| based in the |currentRecord|
+   * @param {string} oldValue
+   * @return {MutationRecord}
+   */
+  function getRecordWithOldValue(oldValue) {
+    if (recordWithOldValue)
+      return recordWithOldValue;
+    recordWithOldValue = copyMutationRecord(currentRecord);
+    recordWithOldValue.oldValue = oldValue;
+    return recordWithOldValue;
+  }
+
+  function clearRecords() {
+    currentRecord = recordWithOldValue = undefined;
+  }
+
+  /**
+   * @param {MutationRecord} record
+   * @return {boolean} Whether the record represents a record from the current
+   * mutation event.
+   */
+  function recordRepresentsCurrentMutation(record) {
+    return record === recordWithOldValue || record === currentRecord;
+  }
+
+  /**
+   * Selects which record, if any, to replace the last record in the queue.
+   * This returns |null| if no record should be replaced.
+   *
+   * @param {MutationRecord} lastRecord
+   * @param {MutationRecord} newRecord
+   * @param {MutationRecord}
+   */
+  function selectRecord(lastRecord, newRecord) {
+    if (lastRecord === newRecord)
+      return lastRecord;
+
+    // Check if the the record we are adding represents the same record. If
+    // so, we keep the one with the oldValue in it.
+    if (recordWithOldValue && recordRepresentsCurrentMutation(lastRecord))
+      return recordWithOldValue;
+
+    return null;
+  }
+
+  /**
+   * Class used to represent a registered observer.
+   * @param {MutationObserver} observer
+   * @param {Node} target
+   * @param {MutationObserverInit} options
+   * @constructor
+   */
+  function Registration(observer, target, options) {
+    this.observer = observer;
+    this.target = target;
+    this.options = options;
+    this.transientObservedNodes = [];
+  }
+
+  Registration.prototype = {
+    enqueue: function(record) {
+      var records = this.observer.records_;
+      var length = records.length;
+
+      // There are cases where we replace the last record with the new record.
+      // For example if the record represents the same mutation we need to use
+      // the one with the oldValue. If we get same record (this can happen as we
+      // walk up the tree) we ignore the new record.
+      if (records.length > 0) {
+        var lastRecord = records[length - 1];
+        var recordToReplaceLast = selectRecord(lastRecord, record);
+        if (recordToReplaceLast) {
+          records[length - 1] = recordToReplaceLast;
+          return;
+        }
+      } else {
+        scheduleCallback(this.observer);
+      }
+
+      records[length] = record;
+    },
+
+    addListeners: function() {
+      this.addListeners_(this.target);
+    },
+
+    addListeners_: function(node) {
+      var options = this.options;
+      if (options.attributes)
+        node.addEventListener('DOMAttrModified', this, true);
+
+      if (options.characterData)
+        node.addEventListener('DOMCharacterDataModified', this, true);
+
+      if (options.childList)
+        node.addEventListener('DOMNodeInserted', this, true);
+
+      if (options.childList || options.subtree)
+        node.addEventListener('DOMNodeRemoved', this, true);
+    },
+
+    removeListeners: function() {
+      this.removeListeners_(this.target);
+    },
+
+    removeListeners_: function(node) {
+      var options = this.options;
+      if (options.attributes)
+        node.removeEventListener('DOMAttrModified', this, true);
+
+      if (options.characterData)
+        node.removeEventListener('DOMCharacterDataModified', this, true);
+
+      if (options.childList)
+        node.removeEventListener('DOMNodeInserted', this, true);
+
+      if (options.childList || options.subtree)
+        node.removeEventListener('DOMNodeRemoved', this, true);
+    },
+
+    /**
+     * Adds a transient observer on node. The transient observer gets removed
+     * next time we deliver the change records.
+     * @param {Node} node
+     */
+    addTransientObserver: function(node) {
+      // Don't add transient observers on the target itself. We already have all
+      // the required listeners set up on the target.
+      if (node === this.target)
+        return;
+
+      this.addListeners_(node);
+      this.transientObservedNodes.push(node);
+      var registrations = registrationsTable.get(node);
+      if (!registrations)
+        registrationsTable.set(node, registrations = []);
+
+      // We know that registrations does not contain this because we already
+      // checked if node === this.target.
+      registrations.push(this);
+    },
+
+    removeTransientObservers: function() {
+      var transientObservedNodes = this.transientObservedNodes;
+      this.transientObservedNodes = [];
+
+      transientObservedNodes.forEach(function(node) {
+        // Transient observers are never added to the target.
+        this.removeListeners_(node);
+
+        var registrations = registrationsTable.get(node);
+        for (var i = 0; i < registrations.length; i++) {
+          if (registrations[i] === this) {
+            registrations.splice(i, 1);
+            // Each node can only have one registered observer associated with
+            // this observer.
+            break;
+          }
+        }
+      }, this);
+    },
+
+    handleEvent: function(e) {
+      // Stop propagation since we are managing the propagation manually.
+      // This means that other mutation events on the page will not work
+      // correctly but that is by design.
+      e.stopImmediatePropagation();
+
+      switch (e.type) {
+        case 'DOMAttrModified':
+          // http://dom.spec.whatwg.org/#concept-mo-queue-attributes
+
+          var name = e.attrName;
+          var namespace = e.relatedNode.namespaceURI;
+          var target = e.target;
+
+          // 1.
+          var record = new getRecord('attributes', target);
+          record.attributeName = name;
+          record.attributeNamespace = namespace;
+
+          // 2.
+          var oldValue =
+              e.attrChange === MutationEvent.ADDITION ? null : e.prevValue;
+
+          forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+            // 3.1, 4.2
+            if (!options.attributes)
+              return;
+
+            // 3.2, 4.3
+            if (options.attributeFilter && options.attributeFilter.length &&
+                options.attributeFilter.indexOf(name) === -1 &&
+                options.attributeFilter.indexOf(namespace) === -1) {
+              return;
+            }
+            // 3.3, 4.4
+            if (options.attributeOldValue)
+              return getRecordWithOldValue(oldValue);
+
+            // 3.4, 4.5
+            return record;
+          });
+
+          break;
+
+        case 'DOMCharacterDataModified':
+          // http://dom.spec.whatwg.org/#concept-mo-queue-characterdata
+          var target = e.target;
+
+          // 1.
+          var record = getRecord('characterData', target);
+
+          // 2.
+          var oldValue = e.prevValue;
+
+
+          forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+            // 3.1, 4.2
+            if (!options.characterData)
+              return;
+
+            // 3.2, 4.3
+            if (options.characterDataOldValue)
+              return getRecordWithOldValue(oldValue);
+
+            // 3.3, 4.4
+            return record;
+          });
+
+          break;
+
+        case 'DOMNodeRemoved':
+          this.addTransientObserver(e.target);
+          // Fall through.
+        case 'DOMNodeInserted':
+          // http://dom.spec.whatwg.org/#concept-mo-queue-childlist
+          var target = e.relatedNode;
+          var changedNode = e.target;
+          var addedNodes, removedNodes;
+          if (e.type === 'DOMNodeInserted') {
+            addedNodes = [changedNode];
+            removedNodes = [];
+          } else {
+
+            addedNodes = [];
+            removedNodes = [changedNode];
+          }
+          var previousSibling = changedNode.previousSibling;
+          var nextSibling = changedNode.nextSibling;
+
+          // 1.
+          var record = getRecord('childList', target);
+          record.addedNodes = addedNodes;
+          record.removedNodes = removedNodes;
+          record.previousSibling = previousSibling;
+          record.nextSibling = nextSibling;
+
+          forEachAncestorAndObserverEnqueueRecord(target, function(options) {
+            // 2.1, 3.2
+            if (!options.childList)
+              return;
+
+            // 2.2, 3.3
+            return record;
+          });
+
+      }
+
+      clearRecords();
+    }
+  };
+
+  global.JsMutationObserver = JsMutationObserver;
+
+  if (!global.MutationObserver)
+    global.MutationObserver = JsMutationObserver;
+
+
+})(this);
+
 window.CustomElements = window.CustomElements || {flags:{}};
 (function(scope){

 

@@ -152,11 +693,11 @@
 }

 

 

-// TODO(sorvell): on platforms without MutationObserver, mutations may not be 

+// TODO(sorvell): on platforms without MutationObserver, mutations may not be

 // reliable and therefore attached/detached are not reliable.

 // To make these callbacks less likely to fail, we defer all inserts and removes

-// to give a chance for elements to be inserted into dom. 

-// This ensures attachedCallback fires for elements that are created and 

+// to give a chance for elements to be inserted into dom.

+// This ensures attachedCallback fires for elements that are created and

 // immediately added to dom.

 var hasPolyfillMutations = (!window.MutationObserver ||

     (window.MutationObserver === window.JsMutationObserver));

@@ -421,7 +962,7 @@
 // TODO(sorvell): See https://github.com/Polymer/polymer/issues/399
 // we'll address this by defaulting to CE polyfill in the presence of the SD
 // polyfill. This will avoid spamming excess attached/detached callbacks.
-// If there is a compelling need to run CE native with SD polyfill, 
+// If there is a compelling need to run CE native with SD polyfill,
 // we'll need to fix this issue.
 var useNative = !flags.register && hasNative && !window.ShadowDOMPolyfill;
 
@@ -440,6 +981,7 @@
   scope.upgradeSubtree = nop;
   scope.observeDocument = nop;
   scope.upgradeDocument = nop;
+  scope.upgradeDocumentTree = nop;
   scope.takeRecords = nop;
 
 } else {
@@ -615,11 +1157,11 @@
     implement(element, definition);
     // flag as upgraded
     element.__upgraded__ = true;
+    // lifecycle management
+    created(element);
     // there should never be a shadow root on element at this point
     // we require child nodes be upgraded before `created`
     scope.upgradeSubtree(element);
-    // lifecycle management
-    created(element);
     // OUTPUT
     return element;
   }
@@ -633,11 +1175,6 @@
       // getPrototypeOf(Element), we cannot do so when
       // we use mixin, so we install a magic reference
       customMixin(element, definition.prototype, definition.native);
-
-      // Dart note: make sure we pick up the right constructor.
-      // dart2js depends on this for dart:mirrors caching to work.
-      // See tests/html/custom/mirrors_test.dart
-      element.constructor = definition.prototype.constructor;
       element.__proto__ = definition.prototype;
     }
   }
@@ -887,7 +1424,7 @@
     Platform.endOfMicrotask :
     setTimeout;
   async(function() {
-    // set internal 'ready' flag, now document.registerElement will trigger 
+    // set internal 'ready' flag, now document.registerElement will trigger
     // synchronous upgrades
     CustomElements.ready = true;
     // capture blunt profiling data
@@ -924,9 +1461,9 @@
 // When loading at other readyStates, wait for the appropriate DOM event to
 // bootstrap.
 } else {
-  var loadEvent = window.HTMLImports && !HTMLImports.ready
-      ? 'HTMLImportsLoaded'
-      : document.readyState == 'loading' ? 'DOMContentLoaded' : 'load';
+  var loadEvent = window.HTMLImports && !HTMLImports.ready ?
+      'HTMLImportsLoaded' : document.readyState == 'loading' ?
+        'DOMContentLoaded' : 'load';
   window.addEventListener(loadEvent, bootstrap);
 }
 
diff --git a/pkg/custom_element/lib/custom-elements.min.js b/pkg/custom_element/lib/custom-elements.min.js
index e1e6c59..78b0c76 100644
--- a/pkg/custom_element/lib/custom-elements.min.js
+++ b/pkg/custom_element/lib/custom-elements.min.js
@@ -25,4 +25,4 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"undefined"==typeof WeakMap&&!function(){var a=Object.defineProperty,b=Date.now()%1e9,c=function(){this.name="__st"+(1e9*Math.random()>>>0)+(b++ +"__")};c.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}},window.WeakMap=c}(),window.CustomElements=window.CustomElements||{flags:{}},function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.shadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:void c(a,d)}),c(a,d)}function e(a){return h(a)?(i(a),!0):void l(a)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return A.dom&&console.group("upgrade:",b.localName),a.upgrade(b),A.dom&&console.groupEnd(),!0}}function i(a){l(a),r(a)&&d(a,function(a){l(a)})}function j(a){if(E.push(a),!D){D=!0;var b=window.Platform&&window.Platform.endOfMicrotask||setTimeout;b(k)}}function k(){D=!1;for(var a,b=E,c=0,d=b.length;d>c&&(a=b[c]);c++)a();E=[]}function l(a){C?j(function(){m(a)}):m(a)}function m(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("inserted:",a.localName),r(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?A.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.attachedCallback&&(A.dom&&console.log("inserted:",a.localName),a.attachedCallback())),A.dom&&console.groupEnd())}function n(a){o(a),d(a,function(a){o(a)})}function o(a){C?j(function(){p(a)}):p(a)}function p(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("removed:",a.localName),r(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?A.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.detachedCallback&&a.detachedCallback()),A.dom&&console.groupEnd())}function q(a){return window.ShadowDOMPolyfill?ShadowDOMPolyfill.wrapIfNeeded(a):a}function r(a){for(var b=a,c=q(document);b;){if(b==c)return!0;b=b.parentNode||b.host}}function s(a){if(a.shadowRoot&&!a.shadowRoot.__watched){A.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.shadowRoot;b;)t(b),b=b.olderShadowRoot}}function t(a){a.__watched||(w(a),a.__watched=!0)}function u(a){if(A.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(G(a.addedNodes,function(a){a.localName&&g(a)}),G(a.removedNodes,function(a){a.localName&&n(a)}))}),A.dom&&console.groupEnd()}function v(){u(F.takeRecords()),k()}function w(a){F.observe(a,{childList:!0,subtree:!0})}function x(a){w(a)}function y(a){A.dom&&console.group("upgradeDocument: ",a.baseURI.split("/").pop()),g(a),A.dom&&console.groupEnd()}function z(a){a=q(a),y(a);for(var b,c=a.querySelectorAll("link[rel="+B+"]"),d=0,e=c.length;e>d&&(b=c[d]);d++)b.import&&b.import.__parsed&&z(b.import)}var A=window.logFlags||{},B=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",C=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;a.hasPolyfillMutations=C;var D=!1,E=[],F=new MutationObserver(u),G=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.IMPORT_LINK_TYPE=B,a.watchShadow=s,a.upgradeDocumentTree=z,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=x,a.upgradeDocument=y,a.takeRecords=v}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("document.registerElement: first argument `name` must not be empty");if(b.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(b)+"'.");if(m(b))throw new Error("DuplicateDefinitionError: a type with name '"+String(b)+"' is already registered");if(!g.prototype)throw new Error("Options missing required prototype property");return g.__name=b.toLowerCase(),g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),n(g.__name,g),g.ctor=o(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,(a.ready||a.performedInitialDocumentUpgrade)&&a.upgradeDocumentTree(document),g.ctor}function c(a){var b=m(a);return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.__name,c&&(a.is=a.__name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(x(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),b.removeAttribute("unresolved"),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.constructor=b.prototype.constructor,a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){if(!a.setAttribute._polyfilled){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a){l.call(this,a,null,c)},a.setAttribute._polyfilled=!0}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments);var e=this.getAttribute(a);this.attributeChangedCallback&&e!==d&&this.attributeChangedCallback(a,d,e)}function m(a){return a?w[a.toLowerCase()]:void 0}function n(a,b){if(w[a])throw new Error("a type with that name is already registered.");w[a]=b}function o(a){return function(){return f(a)}}function p(a,b){var c=m(b||a);if(c){if(a==c.tag&&b==c.is)return new c.ctor;if(!b&&!c.is)return new c.ctor}if(b){var d=p(a);return d.setAttribute("is",b),d}var d=x(a);return a.indexOf("-")>=0&&h(d,HTMLElement),d}function q(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is"),c=w[b||a.localName];if(c){if(b&&c.tag==a.localName)return g(a,c);if(!b&&!c.extends)return g(a,c)}}}function r(b){var c=y.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var s=a.flags,t=Boolean(document.registerElement),u=!s.register&&t&&!window.ShadowDOMPolyfill;if(u){var v=function(){};a.registry={},a.upgradeElement=v,a.watchShadow=v,a.upgrade=v,a.upgradeAll=v,a.upgradeSubtree=v,a.observeDocument=v,a.upgradeDocument=v,a.takeRecords=v}else{var w={},x=document.createElement.bind(document),y=Node.prototype.cloneNode;document.registerElement=b,document.createElement=p,Node.prototype.cloneNode=r,a.registry=w,a.upgrade=q}document.register=document.registerElement,a.hasNative=t,a.useNative=u}(window.CustomElements),function(a){function b(a){return"link"===a.localName&&a.getAttribute("rel")===c}var c=a.IMPORT_LINK_TYPE,d={selectors:["link[rel="+c+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(d.selectors);e(b,function(a){d[d.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(a){b(a)&&this.parseImport(a)},parseImport:function(a){a.import&&d.parse(a.import)}},e=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.parser=d,a.IMPORT_LINK_TYPE=c}(window.CustomElements),function(a){function b(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.performedInitialDocumentUpgrade=!0;var a=window.Platform&&Platform.endOfMicrotask?Platform.endOfMicrotask:setTimeout;a(function(){CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState||a.flags.eager)b();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var c=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"loading"==document.readyState?"DOMContentLoaded":"load";window.addEventListener(c,b)}else b()}(window.CustomElements),function(){if(HTMLElement.prototype.createShadowRoot){var a=HTMLElement.prototype.createShadowRoot;HTMLElement.prototype.createShadowRoot=function(){var b=a.call(this);return b.host=this,CustomElements.watchShadow(this),b}}if(window.ShadowDOMPolyfill){var b=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],c={};b.forEach(function(a){c[a]=CustomElements[a]}),b.forEach(function(a){CustomElements[a]=function(b){return c[a](window.ShadowDOMPolyfill.wrapIfNeeded(b))}})}if(window.CustomElements&&!CustomElements.useNative){var d=Document.prototype.importNode;Document.prototype.importNode=function(a,b){var c=d.call(this,a,b);return CustomElements.upgradeAll(c),c}}}();
\ No newline at end of file
+"undefined"==typeof WeakMap&&!function(){var a=Object.defineProperty,b=Date.now()%1e9,c=function(){this.name="__st"+(1e9*Math.random()>>>0)+(b++ +"__")};c.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}},window.WeakMap=c}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new WeakMap,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g,a.MutationObserver||(a.MutationObserver=g)}(this),window.CustomElements=window.CustomElements||{flags:{}},function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.shadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:(c(a,d),void 0)}),c(a,d)}function e(a){return h(a)?(i(a),!0):(l(a),void 0)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return A.dom&&console.group("upgrade:",b.localName),a.upgrade(b),A.dom&&console.groupEnd(),!0}}function i(a){l(a),r(a)&&d(a,function(a){l(a)})}function j(a){if(E.push(a),!D){D=!0;var b=window.Platform&&window.Platform.endOfMicrotask||setTimeout;b(k)}}function k(){D=!1;for(var a,b=E,c=0,d=b.length;d>c&&(a=b[c]);c++)a();E=[]}function l(a){C?j(function(){m(a)}):m(a)}function m(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("inserted:",a.localName),r(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?A.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.attachedCallback&&(A.dom&&console.log("inserted:",a.localName),a.attachedCallback())),A.dom&&console.groupEnd())}function n(a){o(a),d(a,function(a){o(a)})}function o(a){C?j(function(){p(a)}):p(a)}function p(a){(a.attachedCallback||a.detachedCallback||a.__upgraded__&&A.dom)&&(A.dom&&console.group("removed:",a.localName),r(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?A.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.detachedCallback&&a.detachedCallback()),A.dom&&console.groupEnd())}function q(a){return window.ShadowDOMPolyfill?ShadowDOMPolyfill.wrapIfNeeded(a):a}function r(a){for(var b=a,c=q(document);b;){if(b==c)return!0;b=b.parentNode||b.host}}function s(a){if(a.shadowRoot&&!a.shadowRoot.__watched){A.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.shadowRoot;b;)t(b),b=b.olderShadowRoot}}function t(a){a.__watched||(w(a),a.__watched=!0)}function u(a){if(A.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(G(a.addedNodes,function(a){a.localName&&g(a)}),G(a.removedNodes,function(a){a.localName&&n(a)}))}),A.dom&&console.groupEnd()}function v(){u(F.takeRecords()),k()}function w(a){F.observe(a,{childList:!0,subtree:!0})}function x(a){w(a)}function y(a){A.dom&&console.group("upgradeDocument: ",a.baseURI.split("/").pop()),g(a),A.dom&&console.groupEnd()}function z(a){a=q(a),y(a);for(var b,c=a.querySelectorAll("link[rel="+B+"]"),d=0,e=c.length;e>d&&(b=c[d]);d++)b.import&&b.import.__parsed&&z(b.import)}var A=window.logFlags||{},B=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",C=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;a.hasPolyfillMutations=C;var D=!1,E=[],F=new MutationObserver(u),G=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.IMPORT_LINK_TYPE=B,a.watchShadow=s,a.upgradeDocumentTree=z,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=x,a.upgradeDocument=y,a.takeRecords=v}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("document.registerElement: first argument `name` must not be empty");if(b.indexOf("-")<0)throw new Error("document.registerElement: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(b)+"'.");if(m(b))throw new Error("DuplicateDefinitionError: a type with name '"+String(b)+"' is already registered");if(!g.prototype)throw new Error("Options missing required prototype property");return g.__name=b.toLowerCase(),g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),n(g.__name,g),g.ctor=o(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,(a.ready||a.performedInitialDocumentUpgrade)&&a.upgradeDocumentTree(document),g.ctor}function c(a){var b=m(a);return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.__name,c&&(a.is=a.__name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(x(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),b.removeAttribute("unresolved"),h(b,c),b.__upgraded__=!0,j(b),a.upgradeSubtree(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){if(!a.setAttribute._polyfilled){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a){l.call(this,a,null,c)},a.setAttribute._polyfilled=!0}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments);var e=this.getAttribute(a);this.attributeChangedCallback&&e!==d&&this.attributeChangedCallback(a,d,e)}function m(a){return a?w[a.toLowerCase()]:void 0}function n(a,b){if(w[a])throw new Error("a type with that name is already registered.");w[a]=b}function o(a){return function(){return f(a)}}function p(a,b){var c=m(b||a);if(c){if(a==c.tag&&b==c.is)return new c.ctor;if(!b&&!c.is)return new c.ctor}if(b){var d=p(a);return d.setAttribute("is",b),d}var d=x(a);return a.indexOf("-")>=0&&h(d,HTMLElement),d}function q(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is"),c=w[b||a.localName];if(c){if(b&&c.tag==a.localName)return g(a,c);if(!b&&!c.extends)return g(a,c)}}}function r(b){var c=y.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var s=a.flags,t=Boolean(document.registerElement),u=!s.register&&t&&!window.ShadowDOMPolyfill;if(u){var v=function(){};a.registry={},a.upgradeElement=v,a.watchShadow=v,a.upgrade=v,a.upgradeAll=v,a.upgradeSubtree=v,a.observeDocument=v,a.upgradeDocument=v,a.upgradeDocumentTree=v,a.takeRecords=v}else{var w={},x=document.createElement.bind(document),y=Node.prototype.cloneNode;document.registerElement=b,document.createElement=p,Node.prototype.cloneNode=r,a.registry=w,a.upgrade=q}document.register=document.registerElement,a.hasNative=t,a.useNative=u}(window.CustomElements),function(a){function b(a){return"link"===a.localName&&a.getAttribute("rel")===c}var c=a.IMPORT_LINK_TYPE,d={selectors:["link[rel="+c+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(d.selectors);e(b,function(a){d[d.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(a){b(a)&&this.parseImport(a)},parseImport:function(a){a.import&&d.parse(a.import)}},e=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.parser=d,a.IMPORT_LINK_TYPE=c}(window.CustomElements),function(a){function b(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.performedInitialDocumentUpgrade=!0;var a=window.Platform&&Platform.endOfMicrotask?Platform.endOfMicrotask:setTimeout;a(function(){CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState||a.flags.eager)b();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var c=window.HTMLImports&&!HTMLImports.ready?"HTMLImportsLoaded":"loading"==document.readyState?"DOMContentLoaded":"load";window.addEventListener(c,b)}else b()}(window.CustomElements),function(){if(HTMLElement.prototype.createShadowRoot){var a=HTMLElement.prototype.createShadowRoot;HTMLElement.prototype.createShadowRoot=function(){var b=a.call(this);return b.host=this,CustomElements.watchShadow(this),b}}if(window.ShadowDOMPolyfill){var b=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],c={};b.forEach(function(a){c[a]=CustomElements[a]}),b.forEach(function(a){CustomElements[a]=function(b){return c[a](window.ShadowDOMPolyfill.wrapIfNeeded(b))}})}if(window.CustomElements&&!CustomElements.useNative){var d=Document.prototype.importNode;Document.prototype.importNode=function(a,b){var c=d.call(this,a,b);return CustomElements.upgradeAll(c),c}}}();
\ No newline at end of file
diff --git a/pkg/custom_element/lib/polyfill.dart b/pkg/custom_element/lib/polyfill.dart
index 939fb36..413d7d6 100644
--- a/pkg/custom_element/lib/polyfill.dart
+++ b/pkg/custom_element/lib/polyfill.dart
@@ -54,12 +54,6 @@
  */
 Future loadCustomElementPolyfill() {
   if (!document.supportsRegister && !js.context.hasProperty('CustomElements')) {
-    if (!MutationObserver.supported) {
-      var script = new ScriptElement()
-          ..src = '/packages/mutation_observer/mutation_observer.js';
-      document.head.append(script);
-    }
-
     var script = new ScriptElement()
         ..src = '/packages/custom_element/custom-elements.debug.js';
     document.head.append(script);
diff --git a/pkg/custom_element/pubspec.yaml b/pkg/custom_element/pubspec.yaml
index 39302d5..95a25ea 100644
--- a/pkg/custom_element/pubspec.yaml
+++ b/pkg/custom_element/pubspec.yaml
@@ -1,14 +1,12 @@
 name: custom_element
-version: 0.9.1+2
+version: 0.9.3
 author: "Polymer.dart Team <web-ui-dev@dartlang.org>"
 homepage: http://www.dartlang.org/
 description: >
   Custom Elements let authors define their own elements. Authors associate code
   with custom tag names, and then use those custom tag names as they would any
   standard tag.
-dependencies:
-  mutation_observer: ">=0.9.0 <0.10.0"
 dev_dependencies:
   unittest: ">=0.9.0 <0.10.0"
 environment:
-  sdk: ">=1.0.0 <2.0.0"
+  sdk: ">=1.2.0-dev.4.0 <2.0.0"
diff --git a/pkg/docgen/bin/docgen.dart b/pkg/docgen/bin/docgen.dart
index 2a116de..f1275c5 100644
--- a/pkg/docgen/bin/docgen.dart
+++ b/pkg/docgen/bin/docgen.dart
@@ -22,7 +22,9 @@
   var includeSdk = results['parse-sdk'] || results['include-sdk'];
   var scriptDir = path.dirname(Platform.script.toFilePath());
   var introduction = includeSdk ? '' : results['introduction'];
-  docgen(results.rest.map(path.normalize).toList(),
+  var files = results.rest.map(path.normalize).toList();
+  if (files.isEmpty) _printHelpAndExit();
+  docgen(files,
       packageRoot: results['package-root'],
       outputToYaml: !results['json'],
       includePrivate: results['include-private'],
@@ -32,7 +34,19 @@
       introFileName: introduction,
       out: results['out'],
       excludeLibraries: excludedLibraries,
-      includeDependentPackages: results['include-dependent-packages']);
+      includeDependentPackages: results['include-dependent-packages'],
+      serve: results['serve'],
+      noDocs: results['no-docs'],
+      startPage: results['startPage']);
+}
+
+/**
+ * Print help if we are passed the help option or invalid arguments.
+ */
+void _printHelpAndExit() {
+  print(_initArgParser().getUsage());
+  print('Usage: dart docgen.dart [OPTIONS] fooDir/barFile');
+  exit(0);
 }
 
 /**
@@ -44,11 +58,7 @@
       help: 'Prints help and usage information.',
       negatable: false,
       callback: (help) {
-        if (help) {
-          print(parser.getUsage());
-          print('Usage: dart docgen.dart [OPTIONS] fooDir/barFile');
-          exit(0);
-        }
+        if (help) _printHelpAndExit();
       });
   parser.addFlag('verbose', abbr: 'v',
       help: 'Output more logging information.', negatable: false,
@@ -72,6 +82,11 @@
   parser.addFlag('append',
       help: 'Append to the docs folder, library_list.json and index.txt',
       defaultsTo: false, negatable: false);
+  parser.addFlag('serve', help: 'Clone the documentation viewer repo locally '
+      '(if not already present) and start a simple server', defaultsTo: false,
+      negatable: false);
+  parser.addFlag('no-docs', help: 'Do not generate any new documentation',
+      defaultsTo: false, negatable: false);
   parser.addOption('introduction',
       help: 'Adds the provided markdown text file as the introduction'
         ' for the generated documentation.', defaultsTo: '');
@@ -87,5 +102,12 @@
         'in the directory with its pubspec. Includes documentation for all '
         'of its dependent packages.',
       defaultsTo: false, negatable: false);
+  parser.addOption('startPage',
+      help: 'By default the viewer will start at the SDK introduction page.'
+        'To start at some other page, e.g. for a package, provide the name '
+        'of the package in this argument, e.g. --startPage=intl will make '
+        'the start page of the viewer be the intl package.',
+        defaultsTo: null);
+
   return parser;
 }
diff --git a/pkg/docgen/lib/docgen.dart b/pkg/docgen/lib/docgen.dart
index 168b637..bb50090 100644
--- a/pkg/docgen/lib/docgen.dart
+++ b/pkg/docgen/lib/docgen.dart
@@ -26,9 +26,11 @@
 import 'src/io.dart';
 import '../../../sdk/lib/_internal/compiler/compiler.dart' as api;
 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart'
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart'
+    as dart2js_mirrors;
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart'
     as dart2js;
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart'
     as dart2js_util;
 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
@@ -96,12 +98,6 @@
 [Writing API Documentation](https://code.google.com/p/dart/wiki/WritingApiDocumentation).
 """;
 
-// TODO(efortuna): The use of this field is odd (this is based on how it was
-// originally used. Try to cleanup.
-/// Index of all indexable items. This also ensures that no class is
-/// created more than once.
-Map<String, Indexable> entityMap = new Map<String, Indexable>();
-
 /// Docgen constructor initializes the link resolver for markdown parsing.
 /// Also initializes the command line arguments.
 ///
@@ -110,19 +106,38 @@
 /// also be documented.
 /// If [parseSdk] is `true`, then all Dart SDK libraries will be documented.
 /// This option is useful when only the SDK libraries are needed.
+/// If [serve] is `true`, then after generating the documents we fire up a
+/// simple server to view the documentation.
 ///
 /// Returned Future completes with true if document generation is successful.
 Future<bool> docgen(List<String> files, {String packageRoot,
     bool outputToYaml: true, bool includePrivate: false, bool includeSdk: false,
     bool parseSdk: false, bool append: false, String introFileName: '',
     out: _DEFAULT_OUTPUT_DIRECTORY, List<String> excludeLibraries : const [],
-    bool includeDependentPackages: false}) {
-  return _Generator.generateDocumentation(files, packageRoot: packageRoot,
-      outputToYaml: outputToYaml, includePrivate: includePrivate,
-      includeSdk: includeSdk, parseSdk: parseSdk, append: append,
-      introFileName: introFileName, out: out,
-      excludeLibraries: excludeLibraries,
-      includeDependentPackages: includeDependentPackages);
+    bool includeDependentPackages: false, bool serve: false,
+    bool noDocs: false, String startPage}) {
+  var result;
+  if (!noDocs) {
+    _Viewer.ensureMovedViewerCode();
+    result = _Generator.generateDocumentation(files, packageRoot: packageRoot,
+        outputToYaml: outputToYaml, includePrivate: includePrivate,
+        includeSdk: includeSdk, parseSdk: parseSdk, append: append,
+        introFileName: introFileName, out: out,
+        excludeLibraries: excludeLibraries,
+        includeDependentPackages: includeDependentPackages,
+        startPage: startPage);
+    _Viewer.addBackViewerCode();
+    if (serve) {
+      result.then((success) {
+        if (success) {
+          _Viewer._cloneAndServe();
+        }
+      });
+    }
+  } else if (serve) {
+    _Viewer._cloneAndServe();
+  }
+  return result;
 }
 
 /// Analyzes set of libraries by getting a mirror system and triggers the
@@ -152,15 +167,15 @@
   String get docName {
     if (mirror == null) return '';
     if (mirror is LibraryMirror) {
-      return mirror.qualifiedName.replaceAll('.','-');
+      return dart2js_util.qualifiedNameOf(mirror).replaceAll('.','-');
     }
     var mirrorOwner = mirror.owner;
-    if (mirrorOwner == null) return mirror.qualifiedName;
-    var simpleName = mirror.simpleName;
+    if (mirrorOwner == null) return dart2js_util.qualifiedNameOf(mirror);
+    var simpleName = dart2js_util.nameOf(mirror);
     if (mirror is MethodMirror && (mirror as MethodMirror).isConstructor) {
       // We name constructors specially -- repeating the class name and a
       // "-" to separate the constructor from its name (if any).
-      simpleName = '${mirrorOwner.simpleName}-$simpleName';
+      simpleName = '${dart2js_util.nameOf(mirrorOwner)}-$simpleName';
     }
     return Indexable.getDocgenObject(mirrorOwner, owner).docName + '.' +
         simpleName;
@@ -189,18 +204,19 @@
 /// Docgen representation of an item to be documented, that wraps around a
 /// dart2js mirror.
 abstract class MirrorBased {
+  /// The original dart2js mirror around which this object wraps.
   DeclarationMirror get mirror;
 
   /// Returns a list of meta annotations assocated with a mirror.
   List<Annotation> _createAnnotations(DeclarationMirror mirror,
       Library owningLibrary) {
     var annotationMirrors = mirror.metadata.where((e) =>
-        e is dart2js.Dart2JsConstructedConstantMirror);
+        e is dart2js_mirrors.Dart2JsConstructedConstantMirror);
     var annotations = [];
     annotationMirrors.forEach((annotation) {
       var docgenAnnotation = new Annotation(annotation, owningLibrary);
       if (!_SKIPPED_ANNOTATIONS.contains(
-          docgenAnnotation.mirror.qualifiedName)) {
+          dart2js_util.qualifiedNameOf(docgenAnnotation.mirror))) {
         annotations.add(docgenAnnotation);
       }
     });
@@ -208,8 +224,14 @@
   }
 }
 
+/// Top level documentation traversal and generation object.
+///
+/// Yes, everything in this class is used statically so this technically doesn't
+/// need to be its own class, but it's grouped together for semantic separation
+/// from the other classes and functionality in this library.
 class _Generator {
-  static var _outputDirectory;
+  /// The directory where the output docs are generated.
+  static String _outputDirectory;
 
   /// This is set from the command line arguments flag --include-private
   static bool _includePrivate = false;
@@ -220,6 +242,7 @@
   /// --exclude-lib.
   static List<String> _excluded;
 
+  /// Logger for printing out progress of documentation generation.
   static Logger logger = new Logger('Docgen');
 
   /// Docgen constructor initializes the link resolver for markdown parsing.
@@ -237,7 +260,7 @@
        bool includeSdk: false, bool parseSdk: false, bool append: false,
        String introFileName: '', out: _DEFAULT_OUTPUT_DIRECTORY,
        List<String> excludeLibraries : const [],
-       bool includeDependentPackages: false}) {
+       bool includeDependentPackages: false, String startPage}) {
     _excluded = excludeLibraries;
     _includePrivate = includePrivate;
     logger.onRecord.listen((record) => print(record.message));
@@ -259,7 +282,7 @@
         if (mirrorSystem.libraries.isEmpty) {
           throw new StateError('No library mirrors were created.');
         }
-        Indexable.initializeTopLevelLibraries(mirrorSystem);
+        Indexable._initializeTopLevelLibraries(mirrorSystem);
 
         var availableLibraries = mirrorSystem.libraries.values.where(
             (each) => each.uri.scheme == 'file');
@@ -272,10 +295,10 @@
         librariesToDocument.addAll(
             (includeSdk || parseSdk) ? Indexable._sdkLibraries : []);
         librariesToDocument.removeWhere(
-            (x) => _excluded.contains(x.simpleName));
+            (x) => _excluded.contains(dart2js_util.nameOf(x)));
         _documentLibraries(librariesToDocument, includeSdk: includeSdk,
             outputToYaml: outputToYaml, append: append, parseSdk: parseSdk,
-            introFileName: introFileName);
+            introFileName: introFileName, startPage: startPage);
         return true;
       });
   }
@@ -305,56 +328,50 @@
         mode: append ? FileMode.APPEND : FileMode.WRITE);
   }
 
+  /// Resolve all the links in the introductory comments for a given library or
+  /// package as specified by [filename].
+  static String _readIntroductionFile(String fileName, bool includeSdk) {
+    var linkResolver = (name) => Indexable.globalFixReference(name);
+    var defaultText = includeSdk ? _DEFAULT_SDK_INTRODUCTION : '';
+    var introText = defaultText;
+    if (fileName.isNotEmpty) {
+      var introFile = new File(fileName);
+      introText = introFile.existsSync() ? introFile.readAsStringSync() :
+        defaultText;
+    }
+    return markdown.markdownToHtml(introText,
+        linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
+  }
+
   /// Creates documentation for filtered libraries.
   static void _documentLibraries(List<LibraryMirror> libs,
       {bool includeSdk: false, bool outputToYaml: true, bool append: false,
-       bool parseSdk: false, String introFileName: ''}) {
+       bool parseSdk: false, String introFileName: '', String startPage}) {
     libs.forEach((lib) {
       // Files belonging to the SDK have a uri that begins with 'dart:'.
       if (includeSdk || !lib.uri.toString().startsWith('dart:')) {
         var library = generateLibrary(lib);
-        entityMap[library.name] = library;
       }
     });
 
-    var filteredEntities = entityMap.values.where(_isFullChainVisible);
-
-    /*var filteredEntities2 = new Set<MirrorBased>();
-    for (Map<String, Set<MirrorBased>> firstLevel in mirrorToDocgen.values) {
-      for (Set<MirrorBased> items in firstLevel.values) {
-        for (MirrorBased item in items) {
+    var filteredEntities = new Set<Indexable>();
+    for (Map<String, Set<Indexable>> firstLevel in
+        Indexable._mirrorToDocgen.values) {
+      for (Set<Indexable> items in firstLevel.values) {
+        for (Indexable item in items) {
           if (_isFullChainVisible(item)) {
-            filteredEntities2.add(item);
+            if (item is! Method ||
+                (item is Method && item.methodInheritedFrom == null)) {
+              filteredEntities.add(item);
+            }
           }
         }
       }
-    }*/
-
-    /*print('THHHHHEEE DIFFERENCE IS');
-    var set1 = new Set.from(filteredEntities);
-    var set2 = new Set.from(filteredEntities2);
-    var aResult = set2.difference(set1);
-    for (MirrorBased r in aResult) {
-      print('     a result is $r and ${r.docName}');
-    }*/
-    //print(set1.difference(set2));
+    }
 
     // Outputs a JSON file with all libraries and their preview comments.
     // This will help the viewer know what libraries are available to read in.
     var libraryMap;
-    var linkResolver = (name) => Indexable.globalFixReference(name);
-
-    String readIntroductionFile(String fileName, includeSdk) {
-      var defaultText = includeSdk ? _DEFAULT_SDK_INTRODUCTION : '';
-      var introText = defaultText;
-      if (fileName.isNotEmpty) {
-        var introFile = new File(fileName);
-        introText = introFile.existsSync() ? introFile.readAsStringSync() :
-            defaultText;
-      }
-      return markdown.markdownToHtml(introText,
-          linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
-    }
 
     if (append) {
       var docsDir = listDir(_outputDirectory);
@@ -370,16 +387,27 @@
       var intro = libraryMap['introduction'];
       var spacing = intro.isEmpty ? '' : '<br/><br/>';
       libraryMap['introduction'] =
-          "$intro$spacing${readIntroductionFile(introFileName, includeSdk)}";
+          "$intro$spacing${_readIntroductionFile(introFileName, includeSdk)}";
       outputToYaml = libraryMap['filetype'] == 'yaml';
     } else {
       libraryMap = {
         'libraries' : filteredEntities.where((e) =>
             e is Library).map((e) => e.previewMap).toList(),
-        'introduction' : readIntroductionFile(introFileName, includeSdk),
+        'introduction' : _readIntroductionFile(introFileName, includeSdk),
         'filetype' : outputToYaml ? 'yaml' : 'json'
       };
     }
+    _writeOutputFiles(libraryMap, filteredEntities, outputToYaml, append,
+        startPage);
+  }
+
+  /// Output all of the libraries and classes into json or yaml files for
+  /// consumption by a viewer.
+  static void _writeOutputFiles(libraryMap,
+      Iterable<Indexable> filteredEntities, bool outputToYaml, bool append,
+      String startPage) {
+    if (startPage != null) libraryMap['startPage'] = startPage;
+
     _writeToFile(JSON.encode(libraryMap), 'library_list.json');
 
     // Output libraries and classes to file after all information is generated.
@@ -404,6 +432,7 @@
     _writeToFile(JSON.encode(index), 'index.json');
   }
 
+  /// Helper method to serialize the given Indexable out to a file.
   static void _writeIndexableToFile(Indexable result, bool outputToYaml) {
     var outputFile = result.fileName;
     var output;
@@ -427,7 +456,8 @@
      }
   }
 
-
+  /// Helper accessor to determine the full pathname of the root of the dart
+  /// checkout.
   static String get _rootDirectory {
     var scriptDir = path.absolute(path.dirname(Platform.script.toFilePath()));
     var root = scriptDir;
@@ -472,11 +502,6 @@
   static String _obtainPackageRoot(String packageRoot, bool parseSdk,
       List<String> files) {
     if (packageRoot == null && !parseSdk) {
-      // TODO(efortuna): This logic seems not very robust, but it's from the
-      // original version of the code, pre-refactor, so I'm leavingt it for now.
-      // Revisit to make more robust.
-      // TODO(efortuna): See lines 303-311 in
-      // https://codereview.chromium.org/116043013/diff/390001/pkg/docgen/lib/docgen.dart
       var type = FileSystemEntity.typeSync(files.first);
       if (type == FileSystemEntityType.DIRECTORY) {
         var files2 = listDir(files.first, recursive: true);
@@ -570,16 +595,14 @@
     return sdk;
   }
 
+  /// Return true if this item and all of its owners are all visible.
   static bool _isFullChainVisible(Indexable item) {
-    // TODO: reconcile with isVisible.
-    // TODO: Also should be able to take MirrorBased items in general probably.
-    var result = _includePrivate || (!item.isPrivate && (item.owner != null ?
+    return _includePrivate || (!item.isPrivate && (item.owner != null ?
         _isFullChainVisible(item.owner) : true));
-    return result;
   }
 
   /// Currently left public for testing purposes. :-/
-  static Library generateLibrary(dart2js.Dart2JsLibraryMirror library) {
+  static Library generateLibrary(dart2js_mirrors.Dart2JsLibraryMirror library) {
     var result = new Library(library);
     result._findPackage(library);
     logger.fine('Generated library for ${result.name}');
@@ -587,6 +610,134 @@
   }
 }
 
+/// Convenience methods wrapped up in a class to pull down the docgen viewer for
+/// a viewable website, and start up a server for viewing.
+class _Viewer {
+  static String _dartdocViewerString = path.join(Directory.current.path,
+      'dartdoc-viewer');
+  static Directory _dartdocViewerDir = new Directory(_dartdocViewerString);
+  static Directory _topLevelTempDir;
+  static bool movedViewerCode = false;
+
+  /// If our dartdoc-viewer code is already checked out, move it to a temporary
+  /// directory outside of the package directory, so we don't try to process it
+  /// for documentation.
+  static void ensureMovedViewerCode() {
+    // TODO(efortuna): This will need to be modified to run on anyone's package
+    // outside of the checkout!
+    if (_dartdocViewerDir.existsSync()) {
+      _topLevelTempDir = new Directory(
+          _Generator._rootDirectory).createTempSync();
+      _dartdocViewerDir.renameSync(_topLevelTempDir.path);
+    }
+  }
+
+  /// Move the dartdoc-viewer code back into place for "webpage deployment."
+  static void addBackViewerCode() {
+    if (movedViewerCode) _dartdocViewerDir.renameSync(_dartdocViewerString);
+  }
+
+  /// Serve up our generated documentation for viewing in a browser.
+  static void _cloneAndServe() {
+    // If the viewer code is already there, then don't clone again.
+    if (_dartdocViewerDir.existsSync()) {
+      _moveDirectoryAndServe();
+    }
+    else {
+      var processResult = Process.runSync('git', ['clone', '-b', 'master',
+          'git://github.com/dart-lang/dartdoc-viewer.git'],
+          runInShell: true);
+
+      if (processResult.exitCode == 0) {
+        _moveDirectoryAndServe();
+      } else {
+        print('Error cloning git repository:');
+        print('process output: ${processResult.stdout}');
+        print('process stderr: ${processResult.stderr}');
+      }
+    }
+  }
+
+  /// Move the generated json/yaml docs directory to the dartdoc-viewer
+  /// directory, to run as a webpage.
+  static void _moveDirectoryAndServe() {
+    var processResult = Process.runSync('pub', ['update'], runInShell: true,
+        workingDirectory: path.join(_dartdocViewerDir.path, 'client'));
+    print('process output: ${processResult.stdout}');
+    print('process stderr: ${processResult.stderr}');
+
+    var dir = new Directory(_Generator._outputDirectory == null? 'docs' :
+        _Generator._outputDirectory);
+    var webDocsDir = new Directory(path.join(_dartdocViewerDir.path, 'client',
+        'web', 'docs'));
+    if (dir.existsSync()) {
+      // Move the docs folder to dartdoc-viewer/client/web/docs
+      dir.renameSync(webDocsDir.path);
+    }
+
+    if (webDocsDir.existsSync()) {
+      // Compile the code to JavaScript so we can run on any browser.
+      print('Compile app to JavaScript for viewing.');
+      var processResult = Process.runSync('dart', ['deploy.dart'],
+          workingDirectory : path.join(_dartdocViewerDir.path, 'client'),
+          runInShell: true);
+      print('process output: ${processResult.stdout}');
+      print('process stderr: ${processResult.stderr}');
+      _runServer();
+    }
+  }
+
+  /// A simple HTTP server. Implemented here because this is part of the SDK,
+  /// so it shouldn't have any external dependencies.
+  static void _runServer() {
+    // Launch a server to serve out of the directory dartdoc-viewer/client/web.
+    HttpServer.bind('localhost', 8080).then((HttpServer httpServer) {
+      print('Server launched. Navigate your browser to: '
+          'http://localhost:${httpServer.port}');
+      httpServer.listen((HttpRequest request) {
+        var response = request.response;
+        var basePath = path.join(_dartdocViewerDir.path, 'client', 'out',
+            'web');
+        var requestPath = path.join(basePath, request.uri.path.substring(1));
+        bool found = true;
+        var file = new File(requestPath);
+        if (file.existsSync()) {
+          // Set the correct header type.
+          if (requestPath.endsWith('.html')) {
+            response.headers.set('Content-Type', 'text/html');
+          } else if (requestPath.endsWith('.js')) {
+            response.headers.set('Content-Type', 'application/javascript');
+          } else if (requestPath.endsWith('.dart')) {
+            response.headers.set('Content-Type', 'application/dart');
+          } else if (requestPath.endsWith('.css')) {
+            response.headers.set('Content-Type', 'text/css');
+          }
+        } else {
+          if (requestPath == basePath) {
+            response.headers.set('Content-Type', 'text/html');
+            file = new File(path.join(basePath, 'index.html'));
+          } else {
+            print('Path not found: $requestPath');
+            found = false;
+            response.statusCode = HttpStatus.NOT_FOUND;
+            response.close();
+          }
+        }
+
+        if (found) {
+          // Serve up file contents.
+          file.openRead().pipe(response).catchError((e) {
+            print('HttpServer: error while closing the response stream $e');
+          });
+        }
+      },
+      onError: (e) {
+        print('HttpServer: an error occured $e');
+      });
+    });
+  }
+}
+
 /// An item that is categorized in our mirrorToDocgen map, as a distinct,
 /// searchable element.
 ///
@@ -631,14 +782,14 @@
   Indexable(this.mirror) {
     this.isPrivate = _isHidden(mirror);
 
-    var map = _mirrorToDocgen[this.mirror.qualifiedName];
+    var map = _mirrorToDocgen[dart2js_util.qualifiedNameOf(this.mirror)];
     if (map == null) map = new Map<String, Set<Indexable>>();
 
     var set = map[owner.docName];
     if (set == null) set = new Set<Indexable>();
     set.add(this);
     map[owner.docName] = set;
-    _mirrorToDocgen[this.mirror.qualifiedName] = map;
+    _mirrorToDocgen[dart2js_util.qualifiedNameOf(this.mirror)] = map;
   }
 
   /** Walk up the owner chain to find the owning library. */
@@ -647,7 +798,7 @@
     return _getOwningLibrary(indexable.owner);
   }
 
-  static initializeTopLevelLibraries(MirrorSystem mirrorSystem) {
+  static _initializeTopLevelLibraries(MirrorSystem mirrorSystem) {
     _sdkLibraries = mirrorSystem.libraries.values.where(
         (each) => each.uri.scheme == 'dart');
     _coreLibrary = new Library(_sdkLibraries.singleWhere((lib) =>
@@ -659,8 +810,6 @@
   /// have them replaced with hyphens.
   String get docName;
 
-  markdown.Node fixReferenceWithScope(String name) => null;
-
   /// Converts all [foo] references in comments to <a>libraryName.foo</a>.
   markdown.Node fixReference(String name) {
     // Attempt the look up the whole name up in the scope.
@@ -676,24 +825,36 @@
   String findElementInScope(String name) =>
       _findElementInScope(name, packagePrefix);
 
+  /// For a given name, determine if we need to resolve it as a qualified name
+  /// or a simple name in the source mirors.
   static determineLookupFunc(name) => name.contains('.') ?
       dart2js_util.lookupQualifiedInScope :
         (mirror, name) => mirror.lookupInScope(name);
 
-  // The qualified name (for URL purposes) and the file name are the same,
-  // of the form packageName/ClassName or packageName/ClassName.methodName.
-  // This defines both the URL and the directory structure.
-  String get fileName {
-    return packagePrefix + ownerPrefix + name;
-  }
+  /// The reference to this element based on where it is printed as a
+  /// documentation file and also the unique URL to refer to this item.
+  ///
+  /// The qualified name (for URL purposes) and the file name are the same,
+  /// of the form packageName/ClassName or packageName/ClassName.methodName.
+  /// This defines both the URL and the directory structure.
+  String get fileName =>  packagePrefix + ownerPrefix + name;
 
+  /// The full docName of the owner element, appended with a '.' for this
+  /// object's name to be appended.
   String get ownerPrefix => owner.docName != '' ? owner.docName + '.' : '';
 
+  /// The prefix String to refer to the package that this item is in, for URLs
+  /// and comment resolution.
+  ///
+  /// The prefix can be prepended to a qualified name to get a fully unique
+  /// name among all packages.
   String get packagePrefix => '';
 
-  /// Documentation comment with converted markdown.
+  /// Documentation comment with converted markdown and all links resolved.
   String _comment;
 
+  /// Accessor to documentation comment with markdown converted to html and all
+  /// links resolved.
   String get comment {
     if (_comment != null) return _comment;
 
@@ -706,30 +867,19 @@
 
   set comment(x) => _comment = x;
 
-  String get name => mirror.simpleName;
+  /// The simple name to refer to this item.
+  String get name => dart2js_util.nameOf(mirror);
 
+  /// Accessor to the parent item that owns this item.
+  ///
+  /// "Owning" is defined as the object one scope-level above which this item
+  /// is defined. Ex: The owner for a top level class, would be its enclosing
+  /// library. The owner of a local variable in a method would be the enclosing
+  /// method.
   Indexable get owner => new DummyMirror(mirror.owner);
 
   /// Generates MDN comments from database.json.
-  String _mdnComment() {
-    //Check if MDN is loaded.
-    if (_mdn == null) {
-      // Reading in MDN related json file.
-      var root = _Generator._rootDirectory;
-      var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json');
-      _mdn = JSON.decode(new File(mdnPath).readAsStringSync());
-    }
-    // TODO: refactor OOP
-    if (this is Library) return '';
-    var domAnnotation = this.annotations.firstWhere(
-        (e) => e.mirror.qualifiedName == 'metadata.DomName',
-        orElse: () => null);
-    if (domAnnotation == null) return '';
-    var domName = domAnnotation.parameters.single;
-    var parts = domName.split('.');
-    if (parts.length == 2) return _mdnMemberComment(parts[0], parts[1]);
-    if (parts.length == 1) return _mdnTypeComment(parts[0]);
-  }
+  String _mdnComment();
 
   /// Generates the MDN Comment for variables and method DOM elements.
   String _mdnMemberComment(String type, String member) {
@@ -740,7 +890,7 @@
     if (mdnMember == null) return '';
     if (mdnMember['help'] == null || mdnMember['help'] == '') return '';
     if (mdnMember['url'] == null) return '';
-    return _htmlMdn(mdnMember['help'], mdnMember['url']);
+    return _htmlifyMdn(mdnMember['help'], mdnMember['url']);
   }
 
   /// Generates the MDN Comment for class DOM elements.
@@ -749,10 +899,11 @@
     if (mdnType == null) return '';
     if (mdnType['summary'] == null || mdnType['summary'] == "") return '';
     if (mdnType['srcUrl'] == null) return '';
-    return _htmlMdn(mdnType['summary'], mdnType['srcUrl']);
+    return _htmlifyMdn(mdnType['summary'], mdnType['srcUrl']);
   }
 
-  String _htmlMdn(String content, String url) {
+  /// Encloses the given content in an MDN div and the original source link.
+  String _htmlifyMdn(String content, String url) {
     return '<div class="mdn">' + content.trim() + '<p class="mdn-note">'
         '<a href="' + url.trim() + '">from Mdn</a></p></div>';
   }
@@ -770,7 +921,9 @@
     return finalMap;
   }
 
-  String _getCommentText() {
+  /// Accessor to obtain the raw comment text for a given item, _without_ any
+  /// of the links resolved.
+  String get _commentText {
     String commentText;
     mirror.metadata.forEach((metadata) {
       if (metadata is CommentInstanceMirror) {
@@ -795,10 +948,10 @@
   /// links to the subclasses's version of the methods.
   String _commentToHtml([Indexable resolvingScope]) {
     if (resolvingScope == null) resolvingScope = this;
-    var commentText = _getCommentText();
+    var commentText = _commentText;
     _unresolvedComment = commentText;
 
-    var linkResolver = (name) => resolvingScope.fixReferenceWithScope(name);
+    var linkResolver = (name) => resolvingScope.fixReference(name);
     commentText = commentText == null ? '' :
         markdown.markdownToHtml(commentText.trim(), linkResolver: linkResolver,
             inlineSyntaxes: _MARKDOWN_SYNTAXES);
@@ -809,16 +962,15 @@
   /// The optional parameter [containingLibrary] is contains data for variables
   /// defined at the top level of a library (potentially for exporting
   /// purposes).
-  Map<String, Variable> _createVariables(Map<String, VariableMirror> mirrorMap,
+  Map<String, Variable> _createVariables(Iterable<VariableMirror> mirrors,
       Indexable owner) {
     var data = {};
     // TODO(janicejl): When map to map feature is created, replace the below
     // with a filter. Issue(#9590).
-    mirrorMap.forEach((String mirrorName, VariableMirror mirror) {
+    mirrors.forEach((VariableMirror mirror) {
       if (_Generator._includePrivate || !_isHidden(mirror)) {
-        var variable = new Variable(mirrorName, mirror, owner);
-        entityMap[variable.docName] = variable;
-        data[mirrorName] = entityMap[variable.docName];
+        var mirrorName = dart2js_util.nameOf(mirror);
+        data[mirrorName] = new Variable(mirrorName, mirror, owner);
       }
     });
     return data;
@@ -828,14 +980,12 @@
   /// The optional parameter [containingLibrary] is contains data for variables
   /// defined at the top level of a library (potentially for exporting
   /// purposes).
-  Map<String, Method> _createMethods(Map<String, MethodMirror> mirrorMap,
+  Map<String, Method> _createMethods(Iterable<MethodMirror> mirrors,
       Indexable owner) {
     var group = new Map<String, Method>();
-    mirrorMap.forEach((String mirrorName, MethodMirror mirror) {
+    mirrors.forEach((MethodMirror mirror) {
       if (_Generator._includePrivate || !mirror.isPrivate) {
-        var method = new Method(mirror, owner);
-        entityMap[method.docName] = method;
-        group[mirror.simpleName] = method;
+        group[dart2js_util.nameOf(mirror)] = new Method(mirror, owner);
       }
     });
     return group;
@@ -846,15 +996,16 @@
       Indexable owner) {
     var data = {};
     mirrorList.forEach((ParameterMirror mirror) {
-      data[mirror.simpleName] = new Parameter(mirror, _getOwningLibrary(owner));
+      data[dart2js_util.nameOf(mirror)] =
+          new Parameter(mirror, _getOwningLibrary(owner));
     });
     return data;
   }
 
   /// Returns a map of [Generic] objects constructed from the class mirror.
-  Map<String, Generic> _createGenerics(ClassMirror mirror) {
+  Map<String, Generic> _createGenerics(TypeMirror mirror) {
     return new Map.fromIterable(mirror.typeVariables,
-        key: (e) => e.toString(),
+        key: (e) => dart2js_util.nameOf(e),
         value: (e) => new Generic(e));
   }
 
@@ -862,8 +1013,7 @@
   String toString() => "${super.toString()}(${name.toString()})";
 
   /// Return a map representation of this type.
-  Map toMap() {}
-
+  Map toMap();
 
   /// A declaration is private if itself is private, or the owner is private.
   // Issue(12202) - A declaration is public even if it's owner is private.
@@ -884,13 +1034,14 @@
   ///
   /// An example that starts with _ is _js_helper.
   /// An example that contains ._ is dart._collection.dev
-  // This is because LibraryMirror.isPrivate returns `false` all the time.
   bool _isLibraryPrivate(LibraryMirror mirror) {
-    var sdkLibrary = LIBRARIES[mirror.simpleName];
+    // This method is needed because LibraryMirror.isPrivate returns `false` all
+    // the time.
+    var sdkLibrary = LIBRARIES[dart2js_util.nameOf(mirror)];
     if (sdkLibrary != null) {
       return !sdkLibrary.documented;
-    } else if (mirror.simpleName.startsWith('_') ||
-        mirror.simpleName.contains('._')) {
+    } else if (dart2js_util.nameOf(mirror).startsWith('_') ||
+        dart2js_util.nameOf(mirror).contains('._')) {
       return true;
     }
     return false;
@@ -1011,16 +1162,18 @@
     return null;
   }
 
-  Map expandMethodMap(Map<String, Method> mapToExpand) => {
-    'setters': recurseMap(_filterMap(new Map(), mapToExpand,
+  /// Expand the method map [mapToExpand] into a more detailed map that
+  /// separates out setters, getters, constructors, operators, and methods.
+  Map _expandMethodMap(Map<String, Method> mapToExpand) => {
+    'setters': recurseMap(_filterMap(mapToExpand,
         (key, val) => val.mirror.isSetter)),
-    'getters': recurseMap(_filterMap(new Map(), mapToExpand,
+    'getters': recurseMap(_filterMap(mapToExpand,
         (key, val) => val.mirror.isGetter)),
-    'constructors': recurseMap(_filterMap(new Map(), mapToExpand,
+    'constructors': recurseMap(_filterMap(mapToExpand,
         (key, val) => val.mirror.isConstructor)),
-    'operators': recurseMap(_filterMap(new Map(), mapToExpand,
+    'operators': recurseMap(_filterMap(mapToExpand,
         (key, val) => val.mirror.isOperator)),
-    'methods': recurseMap(_filterMap(new Map(), mapToExpand,
+    'methods': recurseMap(_filterMap(mapToExpand,
         (key, val) => val.mirror.isRegularMethod && !val.mirror.isOperator))
   };
 
@@ -1037,14 +1190,16 @@
     return outputMap;
   }
 
-  Map _filterMap(exported, map, test) {
+  Map _filterMap(Map map, Function test) {
+    var exported = new Map();
     map.forEach((key, value) {
       if (test(key, value)) exported[key] = value;
     });
     return exported;
   }
 
-  bool get _isVisible => _Generator._includePrivate || !isPrivate;
+  /// Accessor to determine if this item and all of its owners are visible.
+  bool get _isVisible => _Generator._isFullChainVisible(this);
 
   /// Given a Dart2jsMirror, find the corresponding Docgen [MirrorBased] object.
   ///
@@ -1056,7 +1211,7 @@
   static Indexable getDocgenObject(DeclarationMirror mirror,
     [Indexable owner]) {
     Map<String, Set<Indexable>> docgenObj =
-        _mirrorToDocgen[mirror.qualifiedName];
+        _mirrorToDocgen[dart2js_util.qualifiedNameOf(mirror)];
     if (docgenObj == null) {
       return new DummyMirror(mirror, owner);
     }
@@ -1090,6 +1245,8 @@
     return new DummyMirror(mirror, owner);
   }
 
+  /// Returns true if [mirror] is the correct type of mirror that this Docgen
+  /// object wraps. (Workaround for the fact that Types are not first class.)
   bool _isValidMirror(DeclarationMirror mirror);
 }
 
@@ -1107,7 +1264,7 @@
   Map<String, Class> errors = {};
 
   String packageName = '';
-  bool hasBeenCheckedForPackage = false;
+  bool _hasBeenCheckedForPackage = false;
   String packageIntro;
 
   /// Returns the [Library] for the given [mirror] if it has already been
@@ -1122,38 +1279,36 @@
 
   Library._(LibraryMirror libraryMirror) : super(libraryMirror) {
     var exported = _calcExportedItems(libraryMirror);
-    var exportedClasses = exported['classes']..addAll(libraryMirror.classes);
+    var exportedClasses = _addAll(exported['classes'],
+        dart2js_util.typesOf(libraryMirror.declarations));
     _findPackage(mirror);
     classes = {};
     typedefs = {};
     errors = {};
-    exportedClasses.forEach((String mirrorName, ClassMirror classMirror) {
-        if (classMirror.isTypedef) {
+    exportedClasses.forEach((String mirrorName, TypeMirror mirror) {
+        if (mirror is TypedefMirror) {
           // This is actually a Dart2jsTypedefMirror, and it does define value,
           // but we don't have visibility to that type.
-          var mirror = classMirror;
           if (_Generator._includePrivate || !mirror.isPrivate) {
-            var aTypedef = new Typedef(mirror, this);
-            entityMap[Indexable.getDocgenObject(mirror).docName] = aTypedef;
-            typedefs[mirror.simpleName] = aTypedef;
+            typedefs[dart2js_util.nameOf(mirror)] = new Typedef(mirror, this);
           }
-        } else {
-          var clazz = new Class(classMirror, this);
+        } else if (mirror is ClassMirror) {
+          var clazz = new Class(mirror, this);
 
           if (clazz.isError()) {
-            errors[classMirror.simpleName] = clazz;
-          } else if (classMirror.isClass) {
-            classes[classMirror.simpleName] = clazz;
+            errors[dart2js_util.nameOf(mirror)] = clazz;
           } else {
-            throw new ArgumentError(
-                '${classMirror.simpleName} - no class type match. ');
+            classes[dart2js_util.nameOf(mirror)] = clazz;
           }
+        } else {
+          throw new ArgumentError(
+              '${dart2js_util.nameOf(mirror)} - no class type match. ');
         }
     });
-    this.functions =  _createMethods(exported['methods']
-      ..addAll(libraryMirror.functions), this);
-    this.variables = _createVariables(exported['variables']
-      ..addAll(libraryMirror.variables), this);
+    this.functions = _createMethods(_addAll(exported['methods'],
+        dart2js_util.methodsOf(libraryMirror.declarations)).values, this);
+    this.variables = _createVariables(_addAll(exported['variables'],
+        dart2js_util.variablesOf(libraryMirror.declarations)).values, this);
   }
 
   /// Look for the specified name starting with the current member, and
@@ -1169,14 +1324,24 @@
     return super.findElementInScope(name);
   }
 
+  String _mdnComment() => '';
+
+  /// Helper that maps [mirrors] to their simple name in map.
+  Map _addAll(Map map, Iterable<DeclarationMirror> mirrors) {
+    for (var mirror in mirrors) {
+      map[dart2js_util.nameOf(mirror)] = mirror;
+    }
+    return map;
+  }
+
   /// For a library's [mirror], determine the name of the package (if any) we
   /// believe it came from (because of its file URI).
   ///
   /// If no package could be determined, we return an empty string.
   String _findPackage(LibraryMirror mirror) {
     if (mirror == null) return '';
-    if (hasBeenCheckedForPackage) return packageName;
-    hasBeenCheckedForPackage = true;
+    if (_hasBeenCheckedForPackage) return packageName;
+    _hasBeenCheckedForPackage = true;
     if (mirror.uri.scheme != 'file') return '';
     // We assume that we are documenting only libraries under package/lib
     packageName = _packageName(mirror);
@@ -1221,8 +1386,6 @@
     return spec["name"];
   }
 
-  markdown.Node fixReferenceWithScope(String name) => fixReference(name);
-
   String get packagePrefix => packageName == null || packageName.isEmpty ?
       '' : '$packageName/';
 
@@ -1237,7 +1400,9 @@
 
   String get name => docName;
 
-  String get docName => mirror.qualifiedName.replaceAll('.','-');
+  String get docName {
+    return dart2js_util.qualifiedNameOf(mirror).replaceAll('.','-');
+  }
 
   /// For the given library determine what items (if any) are exported.
   ///
@@ -1245,7 +1410,7 @@
   /// values of which point to a map of exported name identifiers with values
   /// corresponding to the actual DeclarationMirror.
   Map<String, Map<String, DeclarationMirror>> _calcExportedItems(
-      LibraryMirror library) {
+      LibrarySourceMirror library) {
     var exports = {};
     exports['classes'] = {};
     exports['methods'] = {};
@@ -1257,9 +1422,12 @@
       if (!showExport) {
         // Add all items, and then remove the hidden ones.
         // Ex: "export foo hide bar"
-        exports['classes'].addAll(export.targetLibrary.classes);
-        exports['methods'].addAll(export.targetLibrary.functions);
-        exports['variables'].addAll(export.targetLibrary.variables);
+        _addAll(exports['classes'],
+            dart2js_util.typesOf(export.targetLibrary.declarations));
+        _addAll(exports['methods'],
+            dart2js_util.methodsOf(export.targetLibrary.declarations));
+        _addAll(exports['variables'],
+            dart2js_util.variablesOf(export.targetLibrary.declarations));
       }
       for (CombinatorMirror combinator in export.combinators) {
         for (String identifier in combinator.identifiers) {
@@ -1270,7 +1438,7 @@
             // (such as the polymer package) are curently broken in this
             // way, so we just produce a warning.
             print('Warning identifier $identifier not found in library '
-                '${export.targetLibrary.qualifiedName}');
+                '${dart2js_util.qualifiedNameOf(export.targetLibrary)}');
           } else {
             var subMap = exports['classes'];
             if (declaration is MethodMirror) {
@@ -1302,9 +1470,8 @@
   }
 
   /// Checks if the given name is a key for any of the Class Maps.
-  bool containsKey(String name) {
-    return classes.containsKey(name) || errors.containsKey(name);
-  }
+  bool containsKey(String name) =>
+      classes.containsKey(name) || errors.containsKey(name);
 
   /// Generates a map describing the [Library] object.
   Map toMap() => {
@@ -1312,7 +1479,7 @@
     'qualifiedName': qualifiedName,
     'comment': comment,
     'variables': recurseMap(variables),
-    'functions': expandMethodMap(functions),
+    'functions': _expandMethodMap(functions),
     'classes': {
       'class': classes.values.where((c) => c._isVisible)
         .map((e) => e.previewMap).toList(),
@@ -1330,14 +1497,42 @@
 }
 
 abstract class OwnedIndexable extends Indexable {
+  /// The object one scope-level above which this item is defined.
+  ///
+  /// Ex: The owner for a top level class, would be its enclosing library.
+  /// The owner of a local variable in a method would be the enclosing method.
   Indexable owner;
 
+  /// List of the meta annotations on this item.
+  List<Annotation> annotations;
+
   /// Returns this object's qualified name, but following the conventions
   /// we're using in Dartdoc, which is that library names with dots in them
   /// have them replaced with hyphens.
-  String get docName => owner.docName + '.' + mirror.simpleName;
+  String get docName => owner.docName + '.' + dart2js_util.nameOf(mirror);
 
   OwnedIndexable(DeclarationMirror mirror, this.owner) : super(mirror);
+
+  /// Generates MDN comments from database.json.
+  String _mdnComment() {
+    //Check if MDN is loaded.
+    if (Indexable._mdn == null) {
+      // Reading in MDN related json file.
+      var root = _Generator._rootDirectory;
+      var mdnPath = path.join(root, 'utils/apidoc/mdn/database.json');
+      Indexable._mdn = JSON.decode(new File(mdnPath).readAsStringSync());
+    }
+    var domAnnotation = this.annotations.firstWhere(
+        (e) => e.mirror.qualifiedName == 'metadata.DomName',
+        orElse: () => null);
+    if (domAnnotation == null) return '';
+    var domName = domAnnotation.parameters.single;
+    var parts = domName.split('.');
+    if (parts.length == 2) return _mdnMemberComment(parts[0], parts[1]);
+    if (parts.length == 1) return _mdnTypeComment(parts[0]);
+  }
+
+  String get packagePrefix => owner.packagePrefix;
 }
 
 /// A class containing contents of a Dart class.
@@ -1366,9 +1561,6 @@
   Class superclass;
   bool isAbstract;
 
-  /// List of the meta annotations on the class.
-  List<Annotation> annotations;
-
   /// Make sure that we don't check for inherited comments more than once.
   bool _commentsEnsured = false;
 
@@ -1378,7 +1570,6 @@
     var clazz = Indexable.getDocgenObject(mirror, owner);
     if (clazz is DummyMirror) {
       clazz = new Class._(mirror, owner);
-      entityMap[clazz.docName] = clazz;
     }
     return clazz;
   }
@@ -1401,7 +1592,7 @@
     }
   }
 
-  Class._(ClassMirror classMirror, Indexable owner) :
+  Class._(ClassSourceMirror classMirror, Indexable owner) :
       super(classMirror, owner) {
     inheritedVariables = {};
 
@@ -1413,27 +1604,25 @@
         new Class._possiblyDifferentOwner(classMirror.superclass, owner);
 
     interfaces = superinterfaces.toList();
-    variables = _createVariables(classMirror.variables, this);
-    methods = _createMethods(classMirror.methods, this);
+    variables = _createVariables(
+        dart2js_util.variablesOf(classMirror.declarations), this);
+    methods = _createMethods(classMirror.declarations.values.where(
+        (mirror) => mirror is MethodMirror), this);
     annotations = _createAnnotations(classMirror, _getOwningLibrary(owner));
     generics = _createGenerics(classMirror);
     isAbstract = classMirror.isAbstract;
     inheritedMethods = new Map<String, Method>();
 
-    // Tell all superclasses that you are a subclass, unless you are not
+    // Tell superclass that you are a subclass, unless you are not
     // visible or an intermediary mixin class.
-    if (!classMirror.isNameSynthetic && _isVisible) {
-      parentChain().forEach((parentClass) {
-          parentClass.addSubclass(this);
-      });
+    if (!classMirror.isNameSynthetic && _isVisible && superclass != null) {
+      superclass.addSubclass(this);
     }
 
     if (this.superclass != null) addInherited(superclass);
     interfaces.forEach((interface) => addInherited(interface));
   }
 
-  String get packagePrefix => owner.packagePrefix;
-
   String _lookupInClassAndSuperclasses(String name) {
     var lookupFunc = Indexable.determineLookupFunc(name);
     var classScope = this;
@@ -1459,17 +1648,8 @@
     return result == null ? super.findElementInScope(name) : result;
   }
 
-  markdown.Node fixReferenceWithScope(String name) => fixReference(name);
-
   String get typeName => 'class';
 
-  /// Returns a list of all the parent classes.
-  List<Class> parentChain() {
-    // TODO(efortuna): Seems like we can get rid of this method.
-    var parent = superclass == null ? [] : [superclass];
-    return parent;
-  }
-
   /// Add all inherited variables and methods from the provided superclass.
   /// If [_includePrivate] is true, it also adds the variables and methods from
   /// the superclass.
@@ -1559,7 +1739,7 @@
   /// If a class extends a private superclass, find the closest public
   /// superclass of the private superclass.
   String validSuperclass() {
-    if (superclass == null) return 'dart.core.Object';
+    if (superclass == null) return 'dart-core.Object';
     if (superclass._isVisible) return superclass.qualifiedName;
     return superclass.validSuperclass();
   }
@@ -1577,8 +1757,8 @@
         .map((x) => x.qualifiedName).toList(),
     'variables': recurseMap(variables),
     'inheritedVariables': recurseMap(inheritedVariables),
-    'methods': expandMethodMap(methods),
-    'inheritedMethods': expandMethodMap(inheritedMethods),
+    'methods': _expandMethodMap(methods),
+    'inheritedMethods': _expandMethodMap(inheritedMethods),
     'annotations': annotations.map((a) => a.toMap()).toList(),
     'generics': recurseMap(generics)
   };
@@ -1596,9 +1776,6 @@
   /// Generic information about the typedef.
   Map<String, Generic> generics;
 
-  /// List of the meta annotations on the typedef.
-  List<Annotation> annotations;
-
   /// Returns the [Library] for the given [mirror] if it has already been
   /// created, else creates it.
   factory Typedef(TypedefMirror mirror, Library owningLibrary) {
@@ -1611,9 +1788,9 @@
 
   Typedef._(TypedefMirror mirror, Library owningLibrary) :
       super(mirror, owningLibrary) {
-    returnType = Indexable.getDocgenObject(mirror.value.returnType).docName;
+    returnType = Indexable.getDocgenObject(mirror.referent.returnType).docName;
     generics = _createGenerics(mirror);
-    parameters = _createParameters(mirror.value.parameters, owningLibrary);
+    parameters = _createParameters(mirror.referent.parameters, owningLibrary);
     annotations = _createAnnotations(mirror, owningLibrary);
   }
 
@@ -1627,6 +1804,8 @@
     'generics': recurseMap(generics)
   };
 
+  markdown.Node fixReference(String name) => null;
+
   String get typeName => 'typedef';
 
   bool _isValidMirror(DeclarationMirror mirror) => mirror is TypedefMirror;
@@ -1641,9 +1820,6 @@
   Type type;
   String _variableName;
 
-  /// List of the meta annotations on the variable.
-  List<Annotation> annotations;
-
   factory Variable(String variableName, VariableMirror mirror,
       Indexable owner) {
     var variable = Indexable.getDocgenObject(mirror);
@@ -1676,8 +1852,6 @@
     'annotations': annotations.map((a) => a.toMap()).toList()
   };
 
-  String get packagePrefix => owner.packagePrefix;
-
   String get typeName => 'property';
 
   get comment {
@@ -1688,8 +1862,6 @@
     return super.comment;
   }
 
-  markdown.Node fixReferenceWithScope(String name) => fixReference(name);
-
   String findElementInScope(String name) {
     var lookupFunc = Indexable.determineLookupFunc(name);
     var result = lookupFunc(mirror, name);
@@ -1726,10 +1898,7 @@
   /// Qualified name to state where the comment is inherited from.
   String commentInheritedFrom = "";
 
-  /// List of the meta annotations on the method.
-  List<Annotation> annotations;
-
-  factory Method(MethodMirror mirror, Indexable owner, // Indexable newOwner.
+  factory Method(MethodMirror mirror, Indexable owner,
       [Method methodInheritedFrom]) {
     var method = Indexable.getDocgenObject(mirror, owner);
     if (method is DummyMirror) {
@@ -1748,13 +1917,9 @@
     annotations = _createAnnotations(mirror, _getOwningLibrary(owner));
   }
 
-  String get packagePrefix => owner.packagePrefix;
-
   Method get originallyInheritedFrom => methodInheritedFrom == null ?
       this : methodInheritedFrom.originallyInheritedFrom;
 
-  markdown.Node fixReferenceWithScope(String name) => fixReference(name);
-
   /// Look for the specified name starting with the current member, and
   /// progressively working outward to the current library scope.
   String findElementInScope(String name) {
@@ -1786,7 +1951,8 @@
     if ((mirror as MethodMirror).isConstructor) {
       // We name constructors specially -- including the class name again and a
       // "-" to separate the constructor from its name (if any).
-      return '${owner.docName}.${mirror.owner.simpleName}-${mirror.simpleName}';
+      return '${owner.docName}.${dart2js_util.nameOf(mirror.owner)}-'
+             '${dart2js_util.nameOf(mirror)}';
     }
     return super.docName;
   }
@@ -1838,14 +2004,16 @@
     }
     var result = super.comment;
     if (result == '' && methodInheritedFrom != null) {
-      // this should be NOT from the MIRROR, but from the COMMENT
+      // This should be NOT from the MIRROR, but from the COMMENT.
+      methodInheritedFrom.comment; // Ensure comment field has been populated.
       _unresolvedComment = methodInheritedFrom._unresolvedComment;
 
-      var linkResolver = (name) => fixReferenceWithScope(name);
+      var linkResolver = (name) => fixReference(name);
       comment = _unresolvedComment == null ? '' :
         markdown.markdownToHtml(_unresolvedComment.trim(),
             linkResolver: linkResolver, inlineSyntaxes: _MARKDOWN_SYNTAXES);
-      commentInheritedFrom = methodInheritedFrom.commentInheritedFrom;
+      commentInheritedFrom = comment != '' ?
+          methodInheritedFrom.commentInheritedFrom : '';
       result = comment;
     }
     return result;
@@ -1868,11 +2036,11 @@
   List<Annotation> annotations;
 
   Parameter(this.mirror, Library owningLibrary) {
-    name = mirror.simpleName;
+    name = dart2js_util.nameOf(mirror);
     isOptional = mirror.isOptional;
     isNamed = mirror.isNamed;
     hasDefaultValue = mirror.hasDefaultValue;
-    defaultValue = mirror.defaultValue;
+    defaultValue = '${mirror.defaultValue}';
     type = new Type(mirror.type, owningLibrary);
     annotations = _createAnnotations(mirror, owningLibrary);
   }
@@ -1894,8 +2062,8 @@
   TypeVariableMirror mirror;
   Generic(this.mirror);
   Map toMap() => {
-    'name': mirror.toString(),
-    'type': mirror.upperBound.qualifiedName
+    'name': dart2js_util.nameOf(mirror),
+    'type': dart2js_util.qualifiedNameOf(mirror.upperBound)
   };
 }
 
@@ -1936,7 +2104,7 @@
 
   /// Returns a list of [Type] objects constructed from TypeMirrors.
   List<Type> _createTypeGenerics(TypeMirror mirror) {
-    if (mirror is ClassMirror && !mirror.isTypedef) {
+    if (mirror is ClassMirror) {
       var innerList = [];
       mirror.typeArguments.forEach((e) {
         innerList.add(new Type(e, owningLibrary));
@@ -1966,7 +2134,7 @@
 
   Annotation(InstanceMirror originalMirror, this.owningLibrary) {
     mirror = originalMirror.type;
-    parameters = originalMirror.type.variables.values
+    parameters = dart2js_util.variablesOf(originalMirror.type.declarations)
         .where((e) => e.isFinal)
         .map((e) => originalMirror.getField(e.simpleName).reflectee)
         .where((e) => e != null)
@@ -1977,4 +2145,4 @@
     'name': Indexable.getDocgenObject(mirror, owningLibrary).docName,
     'parameters': parameters
   };
-}
\ No newline at end of file
+}
diff --git a/pkg/docgen/test/multi_library_test.dart b/pkg/docgen/test/multi_library_test.dart
index f4d91d9..79a1431 100644
--- a/pkg/docgen/test/multi_library_test.dart
+++ b/pkg/docgen/test/multi_library_test.dart
@@ -6,6 +6,8 @@
 import 'package:unittest/unittest.dart';
 
 import '../lib/docgen.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart'
+    as dart2js_util;
 
 const String DART_LIBRARY_1 = '''
   library testLib;
@@ -104,8 +106,9 @@
   var fileName3 = path.join(TEMP_DIRNAME.path, 'temp3.dart');
   file = new File(fileName3);
   file.writeAsStringSync(DART_LIBRARY_3);
-  return [new Uri.file(fileName), new Uri.file(fileName3),
-      new Uri.file(fileName3)];
+  return [new Uri.file(fileName, windows: Platform.isWindows),
+          new Uri.file(fileName2, windows: Platform.isWindows),
+          new Uri.file(fileName3, windows: Platform.isWindows)];
 }
 
 main() {
@@ -126,8 +129,10 @@
           // Test for linking to parameter [c]
           var importedLib = libraryMirror.libraryDependencies.firstWhere(
             (dep) => dep.isImport).targetLibrary;
-          var aClassMirror = importedLib.classes.values.first;
-          expect(aClassMirror.qualifiedName, 'testLib2.foo.B');
+          var aClassMirror =
+              dart2js_util.classesOf(importedLib.declarations).first;
+          expect(dart2js_util.qualifiedNameOf(aClassMirror),
+                 'testLib2.foo.B');
           var exportedClass = Indexable.getDocgenObject(aClassMirror, library);
           expect(exportedClass is Class, isTrue);
 
@@ -152,10 +157,12 @@
           // Test a third library referencing another exported library in a
           // separate file.
           importedLib = libraryMirror.libraryDependencies.firstWhere(
-            (dep) => dep.isImport && dep.targetLibrary.qualifiedName ==
+            (dep) => dep.isImport &&
+                     dart2js_util.qualifiedNameOf(dep.targetLibrary) ==
             'testLib.bar').targetLibrary;
-          aClassMirror = importedLib.classes.values.first;
-          expect(aClassMirror.qualifiedName, 'testLib.bar.C');
+          aClassMirror = dart2js_util.classesOf(importedLib.declarations).first;
+          expect(dart2js_util.qualifiedNameOf(aClassMirror),
+                 'testLib.bar.C');
           exportedClass = Indexable.getDocgenObject(aClassMirror, library);
           expect(exportedClass is Class, isTrue);
           expect(exportedClass.docName, 'testLib.C');
diff --git a/pkg/docgen/test/single_library_test.dart b/pkg/docgen/test/single_library_test.dart
index 3ce19a3..ea5ad6b 100644
--- a/pkg/docgen/test/single_library_test.dart
+++ b/pkg/docgen/test/single_library_test.dart
@@ -6,6 +6,8 @@
 import 'package:unittest/unittest.dart';
 
 import '../lib/docgen.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart'
+    as dart2js_util;
 
 const String DART_LIBRARY = '''
   library test;
@@ -48,8 +50,8 @@
       file.writeAsStringSync(DART_LIBRARY);
       getMirrorSystem([new Uri.file(fileName)])
         .then(expectAsync1((mirrorSystem) {
-          var testLibraryUri = new Uri(scheme: 'file',
-              path: path.absolute(fileName));
+          var testLibraryUri = new Uri.file(path.absolute(fileName),
+                                            windows: Platform.isWindows);
           var library = new Library(mirrorSystem.libraries[testLibraryUri]);
           expect(library is Library, isTrue);
 
@@ -99,12 +101,14 @@
           /// Testing fixReference
           // Testing Doc comment for class [A].
           var libraryMirror = mirrorSystem.libraries[testLibraryUri];
-          var classMirror = libraryMirror.classes.values.first;
+          var classMirror =
+              dart2js_util.classesOf(libraryMirror.declarations).first;
           var classDocComment = library.fixReference('A').children.first.text;
           expect(classDocComment, 'test.A');
 
           // Test for linking to parameter [A]
-          var method = Indexable.getDocgenObject(classMirror.methods['doThis']);
+          var method = Indexable.getDocgenObject(
+              classMirror.declarations[dart2js_util.symbolOf('doThis')]);
           var methodParameterDocComment = method.fixReference(
               'A').children.first.text;
           expect(methodParameterDocComment, 'test.A.doThis.A');
diff --git a/pkg/intl/example/basic/basic_example.dart b/pkg/intl/example/basic/basic_example.dart
index 41a63a0..4a8c5c3 100644
--- a/pkg/intl/example/basic/basic_example.dart
+++ b/pkg/intl/example/basic/basic_example.dart
@@ -69,5 +69,5 @@
   var dayFormat = intl.date().add_yMMMMEEEEd();
   var time = hmsFormat.format(aDate);
   var day = dayFormat.format(aDate);
-  Intl.withLocale(intl.locale, () => doThisWithTheOutput(operation(time,day)));
+  Intl.withLocale(intl.locale, () => doThisWithTheOutput(operation(time, day)));
 }
diff --git a/pkg/intl/example/basic/basic_example_runner.dart b/pkg/intl/example/basic/basic_example_runner.dart
index 91bbfdd..805d4f7 100644
--- a/pkg/intl/example/basic/basic_example_runner.dart
+++ b/pkg/intl/example/basic/basic_example_runner.dart
@@ -11,4 +11,4 @@
 
 main() {
   setup(runProgram, print);
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/example/basic/messages_all.dart b/pkg/intl/example/basic/messages_all.dart
index 78cb5f0..9265784 100644
--- a/pkg/intl/example/basic/messages_all.dart
+++ b/pkg/intl/example/basic/messages_all.dart
@@ -35,4 +35,4 @@
   var actualLocale = Intl.verifiedLocale(locale, (x) => _findExact(x) != null);
   if (actualLocale == null) return null;
   return _findExact(actualLocale);
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/example/basic/messages_de.dart b/pkg/intl/example/basic/messages_de.dart
index d18c981..c0145c4 100644
--- a/pkg/intl/example/basic/messages_de.dart
+++ b/pkg/intl/example/basic/messages_de.dart
@@ -18,7 +18,7 @@
   get localeName => 'de';
 
   final messages = {
-    "runAt" : (time, day) => Intl.message("Ausgedruckt am $time am $day.")
+    "runAt": (time, day) => Intl.message("Ausgedruckt am $time am $day.")
   };
 }
 
diff --git a/pkg/intl/example/basic/messages_th_th.dart b/pkg/intl/example/basic/messages_th_th.dart
index 59c98dc..5d3813e 100644
--- a/pkg/intl/example/basic/messages_th_th.dart
+++ b/pkg/intl/example/basic/messages_th_th.dart
@@ -18,6 +18,6 @@
   get localeName => 'th_TH';
 
   final messages = {
-    "runAt" : (time, day) => Intl.message('วิ่ง $time on $day.')
+    "runAt": (time, day) => Intl.message('วิ่ง $time on $day.')
   };
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/lib/bidi_formatter.dart b/pkg/intl/lib/bidi_formatter.dart
index 048a9de..5f23d3f 100644
--- a/pkg/intl/lib/bidi_formatter.dart
+++ b/pkg/intl/lib/bidi_formatter.dart
@@ -108,11 +108,11 @@
       if (directionChange) {
         spanDirection = ' dir=${direction.spanText}';
       }
-      result= '<span$spanDirection>$text</span>';
+      result = '<span$spanDirection>$text</span>';
     } else {
       result = text;
     }
-    return result + (resetDir? _resetDir(text, direction, isHtml) : '');
+    return result + (resetDir ? _resetDir(text, direction, isHtml) : '');
   }
 
   /**
@@ -143,7 +143,7 @@
       result = "${marker}$text${Bidi.PDF}";
 
     }
-    return result + (resetDir? _resetDir(text, direction, isHtml) : '');
+    return result + (resetDir ? _resetDir(text, direction, isHtml) : '');
   }
 
   /**
@@ -172,11 +172,7 @@
         (contextDirection == TextDirection.RTL &&
           (direction == TextDirection.LTR ||
            Bidi.endsWithLtr(text, isHtml)))) {
-      if (contextDirection == TextDirection.LTR) {
-        return Bidi.LRM;
-      } else {
-        return Bidi.RLM;
-      }
+      return contextDirection == TextDirection.LTR ? Bidi.LRM : Bidi.RLM;
     } else {
       return '';
     }
diff --git a/pkg/intl/lib/bidi_utils.dart b/pkg/intl/lib/bidi_utils.dart
index e4599da..3ef2c80 100644
--- a/pkg/intl/lib/bidi_utils.dart
+++ b/pkg/intl/lib/bidi_utils.dart
@@ -45,9 +45,8 @@
    * Returns true if [otherDirection] is known to be different from this
    * direction.
    */
-  bool isDirectionChange(TextDirection otherDirection) {
-    return otherDirection != TextDirection.UNKNOWN && this != otherDirection;
-  }
+  bool isDirectionChange(TextDirection otherDirection) =>
+      otherDirection != TextDirection.UNKNOWN && this != otherDirection;
 }
 
 /**
@@ -198,17 +197,14 @@
    * will override existing one in behavior (should work on Chrome, FF, and IE
    * since this was ported directly from the Closure version).
    */
-  static String enforceRtlInHtml(String html) {
-    return _enforceInHtmlHelper(html, 'rtl');
-  }
+  static String enforceRtlInHtml(String html) =>
+      _enforceInHtmlHelper(html, 'rtl');
 
   /**
    * Enforce RTL on both end of the given [text] using unicode BiDi formatting
    * characters RLE and PDF.
    */
-  static String enforceRtlInText(String text) {
-    return '$RLE$text$PDF';
-  }
+  static String enforceRtlInText(String text) => '$RLE$text$PDF';
 
   /**
    * Enforce the [html] snippet in LTR directionality regardless of overall
@@ -218,17 +214,14 @@
    * the whole piece. If the tag already has a direction specified, this new one
    * will override existing one in behavior (tested on FF and IE).
    */
-  static String enforceLtrInHtml(String html) {
-    return _enforceInHtmlHelper(html, 'ltr');
-  }
+  static String enforceLtrInHtml(String html) =>
+      _enforceInHtmlHelper(html, 'ltr');
 
   /**
    * Enforce LTR on both end of the given [text] using unicode BiDi formatting
    * characters LRE and PDF.
    */
-  static String enforceLtrInText(String text) {
-    return '$LRE$text$PDF';
-  }
+  static String enforceLtrInText(String text) => '$LRE$text$PDF';
 
   /**
    * Enforce the [html] snippet in the desired [direction] regardless of overall
@@ -294,16 +287,15 @@
   // See Issue 2979.
   static String _guardBracketHelper(String str, RegExp regexp, [String before,
       String after]) {
-    StringBuffer buffer = new StringBuffer();
+    var buffer = new StringBuffer();
     var startIndex = 0;
-    Iterable matches = regexp.allMatches(str);
-    for (Match match in matches) {
+    regexp.allMatches(str).forEach((match) {
       buffer..write(str.substring(startIndex, match.start))
             ..write(before)
             ..write(str.substring(match.start, match.end))
             ..write(after);
       startIndex = match.end;
-    }
+    });
     return (buffer..write(str.substring(startIndex))).toString();
   }
 
@@ -371,7 +363,7 @@
           && new RegExp('[\u0591-\u05f2]').hasMatch(str.substring(i-1, i))) {
         buf.write('\u05f3');
       } else {
-        buf.write(str.substring(i, i+1));
+        buf.write(str.substring(i, i + 1));
       }
     }
     return buf.toString();
@@ -382,7 +374,6 @@
    * text should be laid out in RTL direction. If [isHtml] is true, the string
    * is HTML or HTML-escaped.
    */
-  static bool detectRtlDirectionality(String str, {bool isHtml: false}) {
-    return estimateDirectionOfText(str, isHtml: isHtml) == TextDirection.RTL;
-  }
+  static bool detectRtlDirectionality(String str, {bool isHtml: false}) =>
+      estimateDirectionOfText(str, isHtml: isHtml) == TextDirection.RTL;
 }
diff --git a/pkg/intl/lib/date_format.dart b/pkg/intl/lib/date_format.dart
index 0a53f48..d2889ec 100644
--- a/pkg/intl/lib/date_format.dart
+++ b/pkg/intl/lib/date_format.dart
@@ -237,18 +237,14 @@
    * something has happened or how long in the future something will happen
    * given a [reference] DateTime relative to the current time.
    */
-  String formatDuration(DateTime reference) {
-    return '';
-  }
+  String formatDuration(DateTime reference) => '';
 
   /**
    * Formats a string indicating how long ago (negative [duration]) or how far
    * in the future (positive [duration]) some time is with respect to a
    * reference [date].
    */
-  String formatDurationFrom(Duration duration, DateTime date) {
-    return '';
-  }
+  String formatDurationFrom(Duration duration, DateTime date) => '';
 
   /**
    * Given user input, attempt to parse the [inputString] into the anticipated
@@ -259,10 +255,9 @@
     // TODO(alanknight): The Closure code refers to special parsing of numeric
     // values with no delimiters, which we currently don't do. Should we?
     var dateFields = new _DateBuilder();
-    if (utc) dateFields.utc=true;
+    if (utc) dateFields.utc = true;
     var stream = new _Stream(inputString);
-    _formatFields.forEach(
-        (each) => each.parse(stream, dateFields));
+    _formatFields.forEach((f) => f.parse(stream, dateFields));
     return dateFields.asDate();
   }
 
@@ -270,9 +265,7 @@
    * Given user input, attempt to parse the [inputString] into the anticipated
    * format, treating it as being in UTC.
    */
-  DateTime parseUTC(String inputString) {
-    return parse(inputString, true);
-  }
+  DateTime parseUTC(String inputString) => parse(inputString, true);
 
   /**
    * Return the locale code in which we operate, e.g. 'en_US' or 'pt'.
@@ -497,11 +490,9 @@
    * space to separate the two.
    */
   _appendPattern(String inputPattern, [String separator = ' ']) {
-    if (_pattern == null) {
-      _pattern = inputPattern;
-    } else {
-      _pattern = "$_pattern$separator$inputPattern";
-    }
+    _pattern = _pattern == null ?
+      inputPattern :
+      "$_pattern$separator$inputPattern";
   }
 
   /**
@@ -530,9 +521,7 @@
   get pattern => _pattern;
 
   /** Return the skeletons for our current locale. */
-  Map get _availableSkeletons {
-    return dateTimePatterns[locale];
-  }
+  Map get _availableSkeletons => dateTimePatterns[locale];
 
   /**
    * Return the [DateSymbol] information for the locale. This can be useful
@@ -582,7 +571,7 @@
     if (matched == null) return [];
 
     var parsed = _parsePatternHelper(
-                      pattern.substring(matched.fullPattern().length));
+        pattern.substring(matched.fullPattern().length));
     parsed.add(matched);
     return parsed;
   }
diff --git a/pkg/intl/lib/date_symbol_data_file.dart b/pkg/intl/lib/date_symbol_data_file.dart
index a418a9c..a4a67fe 100644
--- a/pkg/intl/lib/date_symbol_data_file.dart
+++ b/pkg/intl/lib/date_symbol_data_file.dart
@@ -40,6 +40,5 @@
 }
 
 /** Defines how new date symbol entries are created. */
-DateSymbols _createDateSymbol(Map map) {
-  return new DateSymbols.deserializeFromMap(map);
-}
+DateSymbols _createDateSymbol(Map map) =>
+    new DateSymbols.deserializeFromMap(map);
diff --git a/pkg/intl/lib/date_symbol_data_http_request.dart b/pkg/intl/lib/date_symbol_data_http_request.dart
index 20d35a1..3fe56c6 100644
--- a/pkg/intl/lib/date_symbol_data_http_request.dart
+++ b/pkg/intl/lib/date_symbol_data_http_request.dart
@@ -41,6 +41,5 @@
 }
 
 /** Defines how new date symbol entries are created. */
-DateSymbols _createDateSymbol(Map map) {
-  return new DateSymbols.deserializeFromMap(map);
-}
+DateSymbols _createDateSymbol(Map map) =>
+    new DateSymbols.deserializeFromMap(map);
diff --git a/pkg/intl/lib/date_symbols.dart b/pkg/intl/lib/date_symbols.dart
index cd0b9d2..aa76c41 100644
--- a/pkg/intl/lib/date_symbols.dart
+++ b/pkg/intl/lib/date_symbols.dart
@@ -82,34 +82,32 @@
     FIRSTWEEKCUTOFFDAY = map["FIRSTWEEKCUTOFFDAY"];
   }
 
-  Map serializeToMap() {
-    var map = new Map();
-    map["NAME"] = NAME;
-    map["ERAS"] = ERAS;
-    map["ERANAMES"] = ERANAMES;
-    map["NARROWMONTHS"] = NARROWMONTHS;
-    map["STANDALONENARROWMONTHS"] = STANDALONENARROWMONTHS;
-    map["MONTHS"] = MONTHS;
-    map["STANDALONEMONTHS"] = STANDALONEMONTHS;
-    map["SHORTMONTHS"] = SHORTMONTHS;
-    map["STANDALONESHORTMONTHS"] = STANDALONESHORTMONTHS;
-    map["WEEKDAYS"] = WEEKDAYS;
-    map["STANDALONEWEEKDAYS"] = STANDALONEWEEKDAYS;
-    map["SHORTWEEKDAYS"] = SHORTWEEKDAYS;
-    map["STANDALONESHORTWEEKDAYS"] = STANDALONESHORTWEEKDAYS;
-    map["NARROWWEEKDAYS"] = NARROWWEEKDAYS;
-    map["STANDALONENARROWWEEKDAYS"] = STANDALONENARROWWEEKDAYS;
-    map["SHORTQUARTERS"] = SHORTQUARTERS;
-    map["QUARTERS"] = QUARTERS;
-    map["AMPMS"] = AMPMS;
-    map["DATEFORMATS"] = DATEFORMATS;
-    map["TIMEFORMATS"] = TIMEFORMATS;
-    map["AVAILABLEFORMATS"] = AVAILABLEFORMATS;
-    map["FIRSTDAYOFWEEK"] = FIRSTDAYOFWEEK;
-    map["WEEKENDRANGE"] = WEEKENDRANGE;
-    map["FIRSTWEEKCUTOFFDAY"] = FIRSTWEEKCUTOFFDAY;
-    return map;
-  }
+  Map serializeToMap() => {
+    "NAME": NAME,
+    "ERAS": ERAS,
+    "ERANAMES": ERANAMES,
+    "NARROWMONTHS": NARROWMONTHS,
+    "STANDALONENARROWMONTHS": STANDALONENARROWMONTHS,
+    "MONTHS": MONTHS,
+    "STANDALONEMONTHS": STANDALONEMONTHS,
+    "SHORTMONTHS": SHORTMONTHS,
+    "STANDALONESHORTMONTHS": STANDALONESHORTMONTHS,
+    "WEEKDAYS": WEEKDAYS,
+    "STANDALONEWEEKDAYS": STANDALONEWEEKDAYS,
+    "SHORTWEEKDAYS": SHORTWEEKDAYS,
+    "STANDALONESHORTWEEKDAYS": STANDALONESHORTWEEKDAYS,
+    "NARROWWEEKDAYS": NARROWWEEKDAYS,
+    "STANDALONENARROWWEEKDAYS": STANDALONENARROWWEEKDAYS,
+    "SHORTQUARTERS": SHORTQUARTERS,
+    "QUARTERS": QUARTERS,
+    "AMPMS": AMPMS,
+    "DATEFORMATS": DATEFORMATS,
+    "TIMEFORMATS": TIMEFORMATS,
+    "AVAILABLEFORMATS": AVAILABLEFORMATS,
+    "FIRSTDAYOFWEEK": FIRSTDAYOFWEEK,
+    "WEEKENDRANGE": WEEKENDRANGE,
+    "FIRSTWEEKCUTOFFDAY": FIRSTWEEKCUTOFFDAY
+  };
 
   toString() => NAME;
 }
@@ -201,4 +199,4 @@
   'z': 'z', // ABBR_SPECIFIC_TZ
   'zzzz': 'zzzz', // SPECIFIC_TZ
   'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
-};
\ No newline at end of file
+};
diff --git a/pkg/intl/lib/date_time_patterns.dart b/pkg/intl/lib/date_time_patterns.dart
index 8c92c70..d392a22 100644
--- a/pkg/intl/lib/date_time_patterns.dart
+++ b/pkg/intl/lib/date_time_patterns.dart
@@ -20,7 +20,7 @@
   /**
    * Extended set of localized date/time patterns for locale af.
    */
-  'af' : const {
+  'af': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -64,13 +64,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale am.
    */
-  'am' : const {
+  'am': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -114,13 +114,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ar.
    */
-  'ar' : const {
+  'ar': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -164,13 +164,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale bg.
    */
-  'bg' : const {
+  'bg': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -214,13 +214,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale bn.
    */
-  'bn' : const {
+  'bn': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -264,13 +264,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ca.
    */
-  'ca' : const {
+  'ca': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -314,13 +314,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale cs.
    */
-  'cs' : const {
+  'cs': const {
     'd': 'd.', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -364,13 +364,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale da.
    */
-  'da' : const {
+  'da': const {
     'd': 'd.', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -414,13 +414,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale de.
    */
-  'de' : const {
+  'de': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -464,13 +464,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale de_AT.
    */
-  'de_AT' : const {
+  'de_AT': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -514,13 +514,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale de_CH.
    */
-  'de_CH' : const {
+  'de_CH': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -564,13 +564,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale el.
    */
-  'el' : const {
+  'el': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -614,13 +614,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en.
    */
-  'en' : const {
+  'en': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -664,13 +664,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en_AU.
    */
-  'en_AU' : const {
+  'en_AU': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -714,13 +714,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en_GB.
    */
-  'en_GB' : const {
+  'en_GB': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -764,13 +764,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en_IE.
    */
-  'en_IE' : const {
+  'en_IE': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -814,13 +814,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en_IN.
    */
-  'en_IN' : const {
+  'en_IN': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -864,13 +864,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en_SG.
    */
-  'en_SG' : const {
+  'en_SG': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -914,13 +914,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en_US.
    */
-  'en_US' : const {
+  'en_US': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -964,13 +964,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en_ISO.
    */
-  'en_ISO' : const {
+  'en_ISO': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1014,13 +1014,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale en_ZA.
    */
-  'en_ZA' : const {
+  'en_ZA': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1064,13 +1064,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale es.
    */
-  'es' : const {
+  'es': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1114,13 +1114,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale es_419.
    */
-  'es_419' : const {
+  'es_419': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1164,13 +1164,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale et.
    */
-  'et' : const {
+  'et': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1214,13 +1214,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale eu.
    */
-  'eu' : const {
+  'eu': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1264,13 +1264,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale fa.
    */
-  'fa' : const {
+  'fa': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1314,13 +1314,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale fi.
    */
-  'fi' : const {
+  'fi': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1364,13 +1364,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale fil.
    */
-  'fil' : const {
+  'fil': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1414,13 +1414,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale fr.
    */
-  'fr' : const {
+  'fr': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1464,13 +1464,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale fr_CA.
    */
-  'fr_CA' : const {
+  'fr_CA': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1514,13 +1514,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale gl.
    */
-  'gl' : const {
+  'gl': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1564,13 +1564,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale gsw.
    */
-  'gsw' : const {
+  'gsw': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1614,13 +1614,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale gu.
    */
-  'gu' : const {
+  'gu': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1664,13 +1664,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale he.
    */
-  'he' : const {
+  'he': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1714,13 +1714,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale hi.
    */
-  'hi' : const {
+  'hi': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1764,13 +1764,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale hr.
    */
-  'hr' : const {
+  'hr': const {
     'd': 'd.', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1814,13 +1814,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale hu.
    */
-  'hu' : const {
+  'hu': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1864,13 +1864,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale id.
    */
-  'id' : const {
+  'id': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1914,13 +1914,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale in.
    */
-  'in' : const {
+  'in': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -1964,13 +1964,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale is.
    */
-  'is' : const {
+  'is': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2014,13 +2014,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale it.
    */
-  'it' : const {
+  'it': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2064,13 +2064,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale iw.
    */
-  'iw' : const {
+  'iw': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2114,13 +2114,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ja.
    */
-  'ja' : const {
+  'ja': const {
     'd': 'd日', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2164,13 +2164,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale kn.
    */
-  'kn' : const {
+  'kn': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2214,13 +2214,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ko.
    */
-  'ko' : const {
+  'ko': const {
     'd': 'd일', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2264,13 +2264,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ln.
    */
-  'ln' : const {
+  'ln': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2314,13 +2314,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale lt.
    */
-  'lt' : const {
+  'lt': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2364,13 +2364,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale lv.
    */
-  'lv' : const {
+  'lv': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2414,13 +2414,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ml.
    */
-  'ml' : const {
+  'ml': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2464,13 +2464,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale mr.
    */
-  'mr' : const {
+  'mr': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2514,13 +2514,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ms.
    */
-  'ms' : const {
+  'ms': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2564,13 +2564,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale mt.
    */
-  'mt' : const {
+  'mt': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2614,13 +2614,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale nl.
    */
-  'nl' : const {
+  'nl': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2664,13 +2664,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale no.
    */
-  'no' : const {
+  'no': const {
     'd': 'd.', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2714,13 +2714,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale or.
    */
-  'or' : const {
+  'or': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2764,13 +2764,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale pl.
    */
-  'pl' : const {
+  'pl': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2814,13 +2814,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale pt_BR.
    */
-  'pt_BR' : const {
+  'pt_BR': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2864,13 +2864,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale pt_PT.
    */
-  'pt_PT' : const {
+  'pt_PT': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2914,13 +2914,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale pt.
    */
-  'pt' : const {
+  'pt': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -2964,13 +2964,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ro.
    */
-  'ro' : const {
+  'ro': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3014,13 +3014,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ru.
    */
-  'ru' : const {
+  'ru': const {
     'd': 'd', // DAY
     'E': 'ccc', // ABBR_WEEKDAY
     'EEEE': 'cccc', // WEEKDAY
@@ -3064,13 +3064,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale sk.
    */
-  'sk' : const {
+  'sk': const {
     'd': 'd.', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3114,13 +3114,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale sl.
    */
-  'sl' : const {
+  'sl': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3164,13 +3164,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale sq.
    */
-  'sq' : const {
+  'sq': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3214,13 +3214,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale sr.
    */
-  'sr' : const {
+  'sr': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3264,13 +3264,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale sv.
    */
-  'sv' : const {
+  'sv': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3314,13 +3314,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale sw.
    */
-  'sw' : const {
+  'sw': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3364,13 +3364,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ta.
    */
-  'ta' : const {
+  'ta': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3414,13 +3414,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale te.
    */
-  'te' : const {
+  'te': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3464,13 +3464,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale th.
    */
-  'th' : const {
+  'th': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3514,13 +3514,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale tl.
    */
-  'tl' : const {
+  'tl': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3564,13 +3564,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale tr.
    */
-  'tr' : const {
+  'tr': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3614,13 +3614,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale uk.
    */
-  'uk' : const {
+  'uk': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3664,13 +3664,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale ur.
    */
-  'ur' : const {
+  'ur': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3714,13 +3714,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale vi.
    */
-  'vi' : const {
+  'vi': const {
     'd': '\'Ngày\' d', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3764,13 +3764,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale zh_TW.
    */
-  'zh_TW' : const {
+  'zh_TW': const {
     'd': 'd日', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3814,13 +3814,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale zh_CN.
    */
-  'zh_CN' : const {
+  'zh_CN': const {
     'd': 'd日', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3864,13 +3864,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale zh_HK.
    */
-  'zh_HK' : const {
+  'zh_HK': const {
     'd': 'd日', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3914,13 +3914,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale zh.
    */
-  'zh' : const {
+  'zh': const {
     'd': 'd日', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -3964,13 +3964,13 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   },
 
   /**
    * Extended set of localized date/time patterns for locale zu.
    */
-  'zu' : const {
+  'zu': const {
     'd': 'd', // DAY
     'E': 'EEE', // ABBR_WEEKDAY
     'EEEE': 'EEEE', // WEEKDAY
@@ -4014,6 +4014,6 @@
     'v': 'v', // ABBR_GENERIC_TZ
     'z': 'z', // ABBR_SPECIFIC_TZ
     'zzzz': 'zzzz', // SPECIFIC_TZ
-    'ZZZZ': 'ZZZZ'  // ABBR_UTC_TZ
+    'ZZZZ': 'ZZZZ' // ABBR_UTC_TZ
   }
-};
\ No newline at end of file
+};
diff --git a/pkg/intl/lib/extract_messages.dart b/pkg/intl/lib/extract_messages.dart
index 66b2258..aca18da 100644
--- a/pkg/intl/lib/extract_messages.dart
+++ b/pkg/intl/lib/extract_messages.dart
@@ -113,8 +113,7 @@
     if (!validNames.contains(node.methodName.name)) return false;
     if (!(node.target is SimpleIdentifier)) return false;
     SimpleIdentifier target = node.target;
-    if (target.token.toString() != "Intl") return false;
-    return true;
+    return target.token.toString() == "Intl";
   }
 
   Message _expectedInstance(String type) {
@@ -175,7 +174,7 @@
    */
   void visitMethodInvocation(MethodInvocation node) {
     if (!addIntlMessage(node)) {
-      return super.visitMethodInvocation(node);
+      super.visitMethodInvocation(node);
     }
   }
 
@@ -190,10 +189,9 @@
     var reason = checkValidity(node);
     if (reason != null) {
       if (!suppressWarnings) {
-        var err = new StringBuffer();
-        err.write("Skipping invalid Intl.message invocation\n    <$node>\n");
-        err.write("    reason: $reason\n");
-        err.write(_reportErrorLocation(node));
+        var err = new StringBuffer()
+            ..write("Skipping invalid Intl.message invocation\n    <$node>\n")
+            ..writeAll(["    reason: $reason\n", _reportErrorLocation(node)]);
         warnings.add(err.toString());
         print(err);
       }
@@ -252,10 +250,9 @@
         message.messagePieces.addAll(interpolation.pieces);
       } on IntlMessageExtractionException catch (e) {
         message = null;
-        var err = new StringBuffer();
-        err.write("Error $e\n");
-        err.write("Processing <$node>\n");
-        err.write(_reportErrorLocation(node));
+        var err = new StringBuffer()
+            ..writeAll(["Error ", e, "\nProcessing <", node, ">\n"])
+            ..write(_reportErrorLocation(node));
         print(err);
         warnings.add(err);
       }
@@ -304,7 +301,7 @@
  * special-purpose visitor.
  */
 class InterpolationVisitor extends SimpleASTVisitor {
-  Message message;
+  final Message message;
 
   InterpolationVisitor(this.message);
 
@@ -373,7 +370,7 @@
    * A plural or gender always exists in the context of a parent message,
    * which could in turn also be a plural or gender.
    */
-  ComplexMessage parent;
+  final ComplexMessage parent;
 
   /**
    * The pieces of the message. We are given an initial version of this
@@ -381,11 +378,11 @@
    */
   List pieces;
 
-  PluralAndGenderVisitor(this.pieces, this.parent) : super() {}
-
   /** This will be set to true if we find a plural or gender. */
   bool foundPluralOrGender = false;
 
+  PluralAndGenderVisitor(this.pieces, this.parent) : super();
+
   visitInterpolationExpression(InterpolationExpression node) {
     // TODO(alanknight): Provide better errors for malformed expressions.
     if (!looksLikePluralOrGender(node.expression)) return;
@@ -409,8 +406,7 @@
     }
     if (!(node.target is SimpleIdentifier)) return false;
     SimpleIdentifier target = node.target;
-    if (target.token.toString() != "Intl") return false;
-    return true;
+    return target.token.toString() == "Intl";
   }
 
   /**
@@ -423,7 +419,7 @@
 
   /**
    * Create a MainMessage from [node] using the name and
-   * parameters of the last function/method declaration we encountered
+   * parameters of the last function/method declaration we encountered            e
    * and the parameters to the Intl.message call.
    */
   Message messageFromMethodInvocation(MethodInvocation node) {
@@ -445,10 +441,9 @@
         message[key] = interpolation.pieces;
       } on IntlMessageExtractionException catch (e) {
         message = null;
-        var err = new StringBuffer();
-        err.write("Error $e");
-        err.write("Processing <$node>");
-        err.write(_reportErrorLocation(node));
+        var err = new StringBuffer()
+            ..writeAll(["Error ", e, "\nProcessing <", node, ">"])
+            ..write(_reportErrorLocation(node));
         print(err);
         warnings.add(err);
       }
@@ -479,4 +474,4 @@
   const IntlMessageExtractionException([this.message = ""]);
 
   String toString() => "IntlMessageExtractionException: $message";
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/lib/generate_localized.dart b/pkg/intl/lib/generate_localized.dart
index 0095c89..0dbd4bc 100644
--- a/pkg/intl/lib/generate_localized.dart
+++ b/pkg/intl/lib/generate_localized.dart
@@ -66,10 +66,10 @@
    * but it can be any identifier that this program and the output of the
    * translation can agree on as identifying a message.
    */
-  String id;
+  final String id;
 
   /** Our translated version of [originalMessage]. */
-  Message translated;
+  final Message translated;
 
   /** The original message that we are a translation of. */
   MainMessage originalMessage;
@@ -106,20 +106,21 @@
   usableTranslations.sort((a, b) =>
       a.originalMessage.name.compareTo(b.originalMessage.name));
   for (var translation in usableTranslations) {
-    result.write("  ");
-    result.write(translation.originalMessage.toCodeForLocale(locale));
-    result.write("\n\n");
+    result
+        .write("  ")
+        ..write(translation.originalMessage.toCodeForLocale(locale))
+        ..write("\n\n");
   }
   result.write("\n  final messages = const {\n");
   var entries = usableTranslations
       .map((translation) => translation.originalMessage.name)
       .map((name) => "    \"$name\" : $name");
-  result.write(entries.join(",\n"));
-  result.write("\n  };\n}");
+  result
+      ..write(entries.join(",\n"))
+      ..write("\n  };\n}");
 
-  var output = new File(path.join(targetDir,
-      "${generatedFilePrefix}messages_$locale.dart"));
-  output.writeAsStringSync(result.toString());
+  new File(path.join(targetDir,"${generatedFilePrefix}messages_$locale.dart"))
+      ..writeAsStringSync(result.toString());
 }
 
 /**
diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart
index ba517d3..281d2fd 100644
--- a/pkg/intl/lib/intl.dart
+++ b/pkg/intl/lib/intl.dart
@@ -121,11 +121,7 @@
    * preferences).
    */
   Intl([String aLocale]) {
-    if (aLocale != null) {
-      _locale = aLocale;
-    } else {
-      _locale = getCurrentLocale();
-    }
+    _locale = aLocale != null ? aLocale : getCurrentLocale();
   }
 
   /**
@@ -177,9 +173,7 @@
    * Return true if the locale exists, or if it is null. The null case
    * is interpreted to mean that we use the default locale.
    */
-  static bool _localeExists(localeName) {
-    return DateFormat.localeExists(localeName);
-  }
+  static bool _localeExists(localeName) => DateFormat.localeExists(localeName);
 
   /**
    * Given [newLocale] return a locale that we have data for that is similar
diff --git a/pkg/intl/lib/message_lookup_by_library.dart b/pkg/intl/lib/message_lookup_by_library.dart
index c4107dc..58e4115 100644
--- a/pkg/intl/lib/message_lookup_by_library.dart
+++ b/pkg/intl/lib/message_lookup_by_library.dart
@@ -115,4 +115,4 @@
   String get localeName;
 
   toString() => localeName;
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/lib/number_format.dart b/pkg/intl/lib/number_format.dart
index a7acbaf..72f3154 100644
--- a/pkg/intl/lib/number_format.dart
+++ b/pkg/intl/lib/number_format.dart
@@ -88,9 +88,8 @@
    * Create a number format that prints using [newPattern] as it applies in
    * [locale].
    */
-  factory NumberFormat([String newPattern, String locale]) {
-    return new NumberFormat._forPattern(locale, (x) => newPattern);
-  }
+  factory NumberFormat([String newPattern, String locale]) =>
+      new NumberFormat._forPattern(locale, (x) => newPattern);
 
   /** Create a number format that prints as DECIMAL_PATTERN. */
   NumberFormat.decimalPattern([String locale]) :
@@ -136,9 +135,7 @@
    * Return the symbols which are used in our locale. Cache them to avoid
    * repeated lookup.
    */
-  NumberSymbols get symbols {
-    return _symbols;
-  }
+  NumberSymbols get symbols => _symbols;
 
   /**
    * Format [number] according to our pattern and return the formatted string.
@@ -307,9 +304,8 @@
    * because we have digits left of the decimal point, or because there are
    * a minimum number of printable digits greater than 1.
    */
-  bool _hasPrintableIntegerPart(int intValue) {
-    return intValue > 0 || minimumIntegerDigits > 0;
-  }
+  bool _hasPrintableIntegerPart(int intValue) =>
+      intValue > 0 || minimumIntegerDigits > 0;
 
   /**
    * Create a new empty buffer. See comment on [_buffer] variable for why
@@ -364,17 +360,13 @@
    * Returns the prefix for [x] based on whether it's positive or negative.
    * In en_US this would be '' and '-' respectively.
    */
-  String _signPrefix(num x) {
-    return x.isNegative ? _negativePrefix : _positivePrefix;
-  }
+  String _signPrefix(num x) => x.isNegative ? _negativePrefix : _positivePrefix;
 
   /**
    * Returns the suffix for [x] based on wether it's positive or negative.
    * In en_US there are no suffixes for positive or negative.
    */
-  String _signSuffix(num x) {
-    return x.isNegative ? _negativeSuffix : _positiveSuffix;
-  }
+  String _signSuffix(num x) => x.isNegative ? _negativeSuffix : _positiveSuffix;
 
   void _setPattern(String newPattern) {
     if (newPattern == null) return;
@@ -466,10 +458,7 @@
   String _parseAffix() {
     var affix = new StringBuffer();
     inQuote = false;
-    var loop = true;
-    while (loop) {
-      loop = parseCharacterAffix(affix) && pattern.moveNext();
-    }
+    while (parseCharacterAffix(affix) && pattern.moveNext());
     return affix.toString();
   }
 
@@ -482,8 +471,7 @@
     var ch = pattern.current;
     if (ch == null) return false;
     if (ch == _QUOTE) {
-      var nextChar = pattern.peek;
-      if (nextChar == _QUOTE) {
+      if (pattern.peek == _QUOTE) {
         pattern.moveNext();
         affix.write(_QUOTE); // 'don''t'
       } else {
@@ -554,10 +542,8 @@
 
     if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
       // Handle '###.###' and '###.' and '.###'
-      var n = decimalPos;
-      if (n == 0) { // Handle '.###'
-        n++;
-      }
+      // Handle '.###'
+      var n = decimalPos == 0 ? 1 : decimalPos;
       digitRightCount = digitLeftCount - n;
       digitLeftCount = n - 1;
       zeroDigitCount = 1;
@@ -702,8 +688,7 @@
 class _StringIterable extends IterableBase<String> {
   final Iterator<String> iterator;
 
-  _StringIterable(String s)
-      : iterator = _iterator(s);
+  _StringIterable(String s) : iterator = _iterator(s);
 }
 
 /**
@@ -711,8 +696,8 @@
  * gives us a lookahead of one via the [peek] method.
  */
 class _StringIterator implements Iterator<String> {
-  String input;
-  var index = -1;
+  final String input;
+  int index = -1;
   inBounds(i) => i >= 0 && i < input.length;
   _StringIterator(this.input);
   String get current => inBounds(index) ? input[index] : null;
diff --git a/pkg/intl/lib/number_symbols.dart b/pkg/intl/lib/number_symbols.dart
index f45cb2c..1f389f1 100644
--- a/pkg/intl/lib/number_symbols.dart
+++ b/pkg/intl/lib/number_symbols.dart
@@ -33,4 +33,4 @@
                        this.DEF_CURRENCY_CODE});
 
   toString() => NAME;
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/lib/src/date_format_field.dart b/pkg/intl/lib/src/date_format_field.dart
index 14990e6..bf8f810 100644
--- a/pkg/intl/lib/src/date_format_field.dart
+++ b/pkg/intl/lib/src/date_format_field.dart
@@ -88,7 +88,7 @@
   }
 
   void patchQuotes() {
-     if (pattern == "''") {
+    if (pattern == "''") {
       pattern = "'";
     } else {
       pattern = pattern.substring(1, pattern.length - 1);
@@ -109,7 +109,7 @@
 
   /** Format date according to our specification and return the result. */
   String format(DateTime date) {
-      return formatField(date);
+    return formatField(date);
   }
 
   /**
@@ -418,7 +418,7 @@
     throw new UnimplementedError();
   }
 
- /**
+  /**
   * Return a string representation of the object padded to the left with
   * zeros. Primarily useful for numbers.
   */
@@ -428,7 +428,7 @@
     var buffer = new StringBuffer();
     for (var i = 0; i < width - basicString.length; i++) {
       buffer.write('0');
-     }
+    }
     buffer.write(basicString);
     return buffer.toString();
   }
diff --git a/pkg/intl/lib/src/temporary_debugging.dart b/pkg/intl/lib/src/temporary_debugging.dart
index f96b56d..29740c4 100644
--- a/pkg/intl/lib/src/temporary_debugging.dart
+++ b/pkg/intl/lib/src/temporary_debugging.dart
@@ -7,4 +7,4 @@
 
 bool debugLogDateCreation = false;
 
-StringBuffer debugDateCreationLog = new StringBuffer();
\ No newline at end of file
+StringBuffer debugDateCreationLog = new StringBuffer();
diff --git a/pkg/intl/test/data_directory.dart b/pkg/intl/test/data_directory.dart
index df76575..3194364 100644
--- a/pkg/intl/test/data_directory.dart
+++ b/pkg/intl/test/data_directory.dart
@@ -53,4 +53,4 @@
       'Cannot find ${path.join('pkg','intl')} directory.');
 }
 
-String get datesRelativeToIntl => path.join('lib', 'src', 'data', 'dates');
\ No newline at end of file
+String get datesRelativeToIntl => path.join('lib', 'src', 'data', 'dates');
diff --git a/pkg/intl/test/date_time_format_test_stub.dart b/pkg/intl/test/date_time_format_test_stub.dart
index 0a70535..4b75747 100644
--- a/pkg/intl/test/date_time_format_test_stub.dart
+++ b/pkg/intl/test/date_time_format_test_stub.dart
@@ -31,7 +31,7 @@
  * Return a set of a few locales to run just the tests on a small sample.
  */
 List smallSetOfLocales() {
-  return allLocales().sublist(0,10);
+  return allLocales().sublist(0, 10);
 }
 
 /**
@@ -52,7 +52,7 @@
   bool initialized = false;
 
   setUp(() {
-    if(initialized) {
+    if (initialized) {
       return null;
     }
     return initFunction("en_US", dir)
diff --git a/pkg/intl/test/find_default_locale_standalone_test.dart b/pkg/intl/test/find_default_locale_standalone_test.dart
index 2518133..f0df693 100644
--- a/pkg/intl/test/find_default_locale_standalone_test.dart
+++ b/pkg/intl/test/find_default_locale_standalone_test.dart
@@ -17,7 +17,7 @@
     Intl.systemLocale = "xx_YY";
     var callback = expectAsync1(verifyLocale);
     findSystemLocale().then(callback);
-    });
+  });
 }
 
 verifyLocale(_) {
diff --git a/pkg/intl/test/intl_test.dart b/pkg/intl/test/intl_test.dart
index 5533896..d357188 100644
--- a/pkg/intl/test/intl_test.dart
+++ b/pkg/intl/test/intl_test.dart
@@ -10,11 +10,11 @@
 
 main() {
   test("Locale setting doesn't verify the core locale", () {
-      var de = new Intl('de_DE');
-      expect(de.locale, equals('de_DE'));
+    var de = new Intl('de_DE');
+    expect(de.locale, equals('de_DE'));
   });
 
-  test('DateFormat creation does verify the locale', (){
+  test('DateFormat creation does verify the locale', () {
     // TODO(alanknight): We need to make the locale verification be on a per
     // usage basis rather than once for the entire Intl object. The set of
     // locales covered for messages may be different from that for date
@@ -23,7 +23,7 @@
       var de = new Intl('de_DE');
       var format = de.date().add_d();
       expect(format.locale, equals('de'));
-     });
+    });
   });
 
   test("Canonicalizing locales", () {
diff --git a/pkg/intl/test/message_extraction/examples_parsing_test.dart b/pkg/intl/test/message_extraction/examples_parsing_test.dart
index 8a336db..661f622 100644
--- a/pkg/intl/test/message_extraction/examples_parsing_test.dart
+++ b/pkg/intl/test/message_extraction/examples_parsing_test.dart
@@ -22,4 +22,4 @@
     var messages = parseFile(new File(file));
     expect(messages['message2'].examples, {"x" : 3});
   });
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/foo_messages_de_DE.dart b/pkg/intl/test/message_extraction/foo_messages_de_DE.dart
index 18f321c..c790ed5 100644
--- a/pkg/intl/test/message_extraction/foo_messages_de_DE.dart
+++ b/pkg/intl/test/message_extraction/foo_messages_de_DE.dart
@@ -80,4 +80,4 @@
     "types" : types,
     "whereTheyWentMessage" : whereTheyWentMessage
   };
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/foo_messages_fr.dart b/pkg/intl/test/message_extraction/foo_messages_fr.dart
index 723d362..58c71ce 100644
--- a/pkg/intl/test/message_extraction/foo_messages_fr.dart
+++ b/pkg/intl/test/message_extraction/foo_messages_fr.dart
@@ -83,4 +83,4 @@
     "types" : types,
     "whereTheyWentMessage" : whereTheyWentMessage
   };
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/message_extraction_test.dart b/pkg/intl/test/message_extraction/message_extraction_test.dart
index f64153d..b2de632 100644
--- a/pkg/intl/test/message_extraction/message_extraction_test.dart
+++ b/pkg/intl/test/message_extraction/message_extraction_test.dart
@@ -48,7 +48,8 @@
   var files = [dir('intl_messages.json'), dir('translation_fr.json'),
       dir('translation_de_DE.json')];
   files.map((name) => new File(name)).forEach((x) {
-    if (x.existsSync()) x.deleteSync();});
+    if (x.existsSync()) x.deleteSync();
+  });
 }
 
 /**
diff --git a/pkg/intl/test/message_extraction/part_of_sample_with_messages.dart b/pkg/intl/test/message_extraction/part_of_sample_with_messages.dart
index 085459c..b3728fd 100644
--- a/pkg/intl/test/message_extraction/part_of_sample_with_messages.dart
+++ b/pkg/intl/test/message_extraction/part_of_sample_with_messages.dart
@@ -72,4 +72,4 @@
        args: [names, number, combinedGender, place]);
     return nestedMessage(names, number, combinedGender, place);
   }
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/print_to_list.dart b/pkg/intl/test/message_extraction/print_to_list.dart
index e718fc4..f5446d4 100644
--- a/pkg/intl/test/message_extraction/print_to_list.dart
+++ b/pkg/intl/test/message_extraction/print_to_list.dart
@@ -7,4 +7,4 @@
 
 void printOut(String s) {
   lines.add(s);
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/sample_with_messages.dart b/pkg/intl/test/message_extraction/sample_with_messages.dart
index b978ca8..e1a9ac3 100644
--- a/pkg/intl/test/message_extraction/sample_with_messages.dart
+++ b/pkg/intl/test/message_extraction/sample_with_messages.dart
@@ -186,4 +186,4 @@
   var f2 = initializeMessages(de.locale).then((_) => printStuff(de));
   printStuff(english);
   return Future.wait([f1, f2]);
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/message_extraction/verify_messages.dart b/pkg/intl/test/message_extraction/verify_messages.dart
index 2203be6..d368c36 100644
--- a/pkg/intl/test/message_extraction/verify_messages.dart
+++ b/pkg/intl/test/message_extraction/verify_messages.dart
@@ -145,4 +145,4 @@
   verify('5 einige Währung oder anderen.');
   verify('1 Kanadischer dollar');
   verify('2 Kanadischen dollar');
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/test/number_format_test.dart b/pkg/intl/test/number_format_test.dart
index 3b9aed6..07f1db1 100644
--- a/pkg/intl/test/number_format_test.dart
+++ b/pkg/intl/test/number_format_test.dart
@@ -16,7 +16,7 @@
  * Tests the Numeric formatting library in dart.
  */
 var testNumbers = {
-  "0.001":  0.001,
+  "0.001": 0.001,
   "0.01": 0.01,
   "0.1": 0.1,
   "1": 1,
@@ -94,4 +94,4 @@
       expect(formatted, x);
     }
   });
-}
\ No newline at end of file
+}
diff --git a/pkg/intl/tool/generate_locale_data_files.dart b/pkg/intl/tool/generate_locale_data_files.dart
index 4934d66..f60f515 100644
--- a/pkg/intl/tool/generate_locale_data_files.dart
+++ b/pkg/intl/tool/generate_locale_data_files.dart
@@ -69,9 +69,7 @@
 
 void writePatterns(locale, patterns) {
   var file = new File(path.join(dataDirectory, 'patterns', '${locale}.json'));
-  var output = file.openWrite();
-  output.write(JSON.encode(patterns));
-  output.close();
+  file.openWrite()..write(JSON.encode(patterns))..close();
 }
 
 void writeToJSON(dynamic data, IOSink out) {
diff --git a/pkg/observe/lib/html.dart b/pkg/observe/lib/html.dart
index abf333a..2627531 100644
--- a/pkg/observe/lib/html.dart
+++ b/pkg/observe/lib/html.dart
@@ -51,7 +51,12 @@
   }
 }
 
-/** Add or remove CSS class [className] based on the [value]. */
+/**
+ * *Deprecated* use [CssClassSet.toggle] instead.
+ *
+ * Add or remove CSS class [className] based on the [value].
+ */
+@deprecated
 void updateCssClass(Element element, String className, bool value) {
   if (value == true) {
     element.classes.add(className);
@@ -60,11 +65,21 @@
   }
 }
 
-/** Bind a CSS class to the observable [object] and property [path]. */
+/**
+ * *Deprecated* use `class="{{ binding }}"` in your HTML instead. It will also
+ * work on a `<polymer-element>`.
+ *
+ * Bind a CSS class to the observable [object] and property [path].
+ */
+@deprecated
 PathObserver bindCssClass(Element element, String className,
     Observable object, String path) {
 
-  return new PathObserver(object, path)..bindSync((value) {
+  callback(value) {
     updateCssClass(element, className, value);
-  });
+  }
+
+  var obs = new PathObserver(object, path);
+  callback(obs.open(callback));
+  return obs;
 }
diff --git a/pkg/observe/lib/observe.dart b/pkg/observe/lib/observe.dart
index 218a036..1dd83b8 100644
--- a/pkg/observe/lib/observe.dart
+++ b/pkg/observe/lib/observe.dart
@@ -76,25 +76,16 @@
  * form into the second form automatically, to get the best of both worlds.
  */
 library observe;
-import 'src/bind_property.dart';
-import 'src/change_notifier.dart';
-import 'src/change_record.dart';
-import 'src/compound_path_observer.dart';
-import 'src/list_path_observer.dart';
-import 'src/list_diff.dart';
-import 'src/metadata.dart';
-import 'src/observable.dart';
-import 'src/observable_box.dart';
-import 'src/observable_list.dart';
-import 'src/observable_map.dart';
-import 'src/path_observer.dart';
-import 'src/to_observable.dart';
 
+// This library contains code ported from observe-js:
+// https://github.com/Polymer/observe-js/blob/0152d542350239563d0f2cad39d22d3254bd6c2a/src/observe.js
+// We port what is needed for data bindings. Most of the functionality is
+// ported, except where differences are needed for Dart's Observable type.
 
+export 'src/bindable.dart';
 export 'src/bind_property.dart';
 export 'src/change_notifier.dart';
 export 'src/change_record.dart';
-export 'src/compound_path_observer.dart';
 export 'src/list_path_observer.dart';
 export 'src/list_diff.dart' show ListChangeRecord;
 export 'src/metadata.dart';
@@ -102,5 +93,6 @@
 export 'src/observable_box.dart';
 export 'src/observable_list.dart';
 export 'src/observable_map.dart';
+export 'src/observer_transform.dart';
 export 'src/path_observer.dart';
 export 'src/to_observable.dart';
diff --git a/pkg/observe/lib/src/bindable.dart b/pkg/observe/lib/src/bindable.dart
new file mode 100644
index 0000000..636ef30
--- /dev/null
+++ b/pkg/observe/lib/src/bindable.dart
@@ -0,0 +1,35 @@
+// 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.
+
+library observe.src.bindable;
+
+/// An object that can be data bound.
+// Normally this is used with 'package:template_binding'.
+// TODO(jmesserly): Node.bind polyfill calls this "observable"
+abstract class Bindable {
+  // TODO(jmesserly): since we have "value", should open be a void method?
+  // TODO(jmesserly): not sure how I feel about open taking a variable number
+  // of arguments, but it's the easiest way to make CompoundObserver work.
+
+  /// Initiates observation and returns the initial value.
+  /// The callback will be called with the updated [value].
+  ///
+  /// Some subtypes may chose to provide additional arguments, such as
+  /// [PathObserver] providing the old value as the second argument.
+  /// However, they must support callbacks with as few as 0 or 1 argument.
+  /// This can be implemented by performing an "is" type test on the callback.
+  open(callback);
+
+  /// Stops future notifications and frees the reference to the callback passed
+  /// to [open], so its memory can be collected even if this Bindable is alive.
+  void close();
+
+  /// Gets the current value of the bindings.
+  get value;
+
+  /// This can be implemented for two-way bindings. By default does nothing.
+  /// Note: setting the value of a [Bindable] must not call the [callback] with
+  /// the new value. Any pending change notifications must be discarded.
+  set value(newValue) {}
+}
diff --git a/pkg/observe/lib/src/compound_path_observer.dart b/pkg/observe/lib/src/compound_path_observer.dart
deleted file mode 100644
index 1594e08..0000000
--- a/pkg/observe/lib/src/compound_path_observer.dart
+++ /dev/null
@@ -1,115 +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.
-
-library observe.src.compound_path_observer;
-
-import 'dart:async';
-import 'package:observe/observe.dart';
-
-/**
- * CompoundPathObserver is an object which knows how to listen to multiple path
- * values (registered via [addPath]) and invoke a function when one or more
- * of the values have changed. The result of this function will be set into the
- * [value] property. When any value has changed, all current values are provided
- * to the function in the single `values` argument.
- *
- * For example:
- *
- *     var binding = new CompoundPathObserver(computeValue: (values) {
- *       var combinedValue;
- *       // compute combinedValue based on the current values which are provided
- *       return combinedValue;
- *     });
- *     binding.addPath(obj1, path1);
- *     binding.addPath(obj2, path2);
- *     //...
- *     binding.addPath(objN, pathN);
- */
-// TODO(jmesserly): this isn't a full port of CompoundPathObserver. It is only
-// what was needed for TemplateBinding.
-class CompoundPathObserver extends ChangeNotifier {
-  List<PathObserver> _observers = [];
-  List<StreamSubscription> _subs = [];
-  Object _value; // the last computed value
-
-  // TODO(jmesserly): this is public in observe.js
-  final Function _computeValue;
-
-  bool _started = false;
-
-  /** True if [start] has been called, otherwise false. */
-  bool get started => _started;
-
-  bool _scheduled = false;
-
-  /**
-   * Creates a new observer, optionally proving the [computeValue] function
-   * for computing the value. You can also set [schedule] to true if you plan
-   * to invoke [resolve] manually after initial construction of the binding.
-   */
-  CompoundPathObserver({computeValue(List values)})
-      : _computeValue = computeValue;
-
-  int get length => _observers.length;
-
-  @reflectable get value => _value;
-
-  void addPath(model, String path) {
-    if (_started) {
-      throw new StateError('Cannot add more paths once started.');
-    }
-
-    _observers.add(new PathObserver(model, path));
-  }
-
-  void start() {
-    if (_started) return;
-    _started = true;
-
-    final scheduleResolve = _scheduleResolve;
-    for (var observer in _observers) {
-      _subs.add(observer.changes.listen(scheduleResolve));
-    }
-    _resolve();
-  }
-
-  // TODO(rafaelw): Is this the right processing model?
-  // TODO(rafaelw): Consider having a seperate ChangeSummary for
-  // CompoundBindings so to excess dirtyChecks.
-  void _scheduleResolve(_) {
-    if (_scheduled) return;
-    _scheduled = true;
-    scheduleMicrotask(_resolve);
-  }
-
-  void _resolve() {
-    _scheduled = false;
-    if (_observers.isEmpty) return;
-    var newValue = _observers.map((o) => o.value).toList();
-    if (_computeValue != null) newValue = _computeValue(newValue);
-    _value = notifyPropertyChange(#value, _value, newValue);
-  }
-
-  /**
-   * Closes the observer.
-   *
-   * This happens automatically if the [value] property is no longer observed,
-   * but this can also be called explicitly.
-   */
-  void close() {
-    if (_observers.isEmpty) return;
-
-    if (_started) {
-      for (StreamSubscription sub in _subs) {
-        sub.cancel();
-      }
-    }
-    _observers.clear();
-    _subs.clear();
-    _value = null;
-  }
-
-  observed() => start();
-  unobserved() => close();
-}
diff --git a/pkg/observe/lib/src/list_diff.dart b/pkg/observe/lib/src/list_diff.dart
index 6acef80..67a9ff1 100644
--- a/pkg/observe/lib/src/list_diff.dart
+++ b/pkg/observe/lib/src/list_diff.dart
@@ -381,7 +381,7 @@
  */
 List<ListChangeRecord> projectListSplices(List list,
     List<ListChangeRecord> records) {
-  if (records.length == 1) return records;
+  if (records.length <= 1) return records;
 
   var splices = [];
   for (var splice in _createInitialSplices(list, records)) {
diff --git a/pkg/observe/lib/src/microtask.dart b/pkg/observe/lib/src/microtask.dart
deleted file mode 100644
index e4ed2d9..0000000
--- a/pkg/observe/lib/src/microtask.dart
+++ /dev/null
@@ -1,72 +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.
-
-/**
- * *Warning*: this library is **internal**, and APIs are subject to change.
- *
- * Wraps a callback using [wrapMicrotask] and provides the ability to pump all
- * observable objects and [scheduleMicrotask] calls via
- * [performMicrotaskCheckpoint].
- */
-library observe.src.microtask;
-
-import 'dart:async' show Completer, runZoned, ZoneSpecification;
-import 'dart:collection';
-import 'package:observe/observe.dart' show Observable;
-
-// TODO(jmesserly): remove "microtask" from these names and instead import
-// the library "as microtask"?
-
-/**
- * This change pumps events relevant to observers and data-binding tests.
- * This must be used inside an [observeTest].
- *
- * Executes all pending [scheduleMicrotask] calls on the event loop, as well as
- * performing [Observable.dirtyCheck], until there are no more pending events.
- * It will always dirty check at least once.
- */
-// TODO(jmesserly): do we want to support nested microtasks similar to nested
-// zones? Instead of a single pending list we'd need one per wrapMicrotask,
-// and [performMicrotaskCheckpoint] would only run pending callbacks
-// corresponding to the innermost wrapMicrotask body.
-void performMicrotaskCheckpoint() {
-  Observable.dirtyCheck();
-
-  while (_pending.isNotEmpty) {
-
-    for (int len = _pending.length; len > 0 && _pending.isNotEmpty; len--) {
-      final callback = _pending.removeFirst();
-      try {
-        callback();
-      } catch (e, s) {
-        new Completer().completeError(e, s);
-      }
-    }
-
-    Observable.dirtyCheck();
-  }
-}
-
-final Queue<Function> _pending = new Queue<Function>();
-
-/**
- * Wraps the [body] in a zone that supports [performMicrotaskCheckpoint],
- * and returns the body.
- */
-// TODO(jmesserly): deprecate? this doesn't add much over runMicrotask.
-wrapMicrotask(body()) => () => runMicrotask(body);
-
-/**
- * Runs the [body] in a zone that supports [performMicrotaskCheckpoint],
- * and returns the result.
- */
-runMicrotask(body()) => runZoned(() {
-  try {
-    return body();
-  } finally {
-    performMicrotaskCheckpoint();
-  }
-}, zoneSpecification: new ZoneSpecification(
-    scheduleMicrotask: (self, parent, zone, callback) => _pending.add(callback))
-);
diff --git a/pkg/observe/lib/src/observable_list.dart b/pkg/observe/lib/src/observable_list.dart
index be25afa..f7052ff 100644
--- a/pkg/observe/lib/src/observable_list.dart
+++ b/pkg/observe/lib/src/observable_list.dart
@@ -255,12 +255,17 @@
     notifyPropertyChange(#isNotEmpty, oldValue != 0, newValue != 0);
   }
 
+  void discardListChages() {
+    // Leave _listRecords set so we don't schedule another delivery.
+    if (_listRecords != null) _listRecords = [];
+  }
+
   bool deliverListChanges() {
     if (_listRecords == null) return false;
     var records = projectListSplices(this, _listRecords);
     _listRecords = null;
 
-    if (_hasListObservers) {
+    if (_hasListObservers && !records.isEmpty) {
       _listChanges.add(new UnmodifiableListView<ListChangeRecord>(records));
       return true;
     }
@@ -284,4 +289,24 @@
   static List<ListChangeRecord> calculateChangeRecords(
       List<Object> oldValue, List<Object> newValue) =>
       calcSplices(newValue, 0, newValue.length, oldValue, 0, oldValue.length);
+
+  /**
+   * Updates the [previous] list using the change [records]. For added items,
+   * the [current] list is used to find the current value.
+   */
+  static void applyChangeRecords(List<Object> previous, List<Object> current,
+      List<ListChangeRecord> changeRecords) {
+
+    if (identical(previous, current)) {
+      throw new ArgumentError("can't use same list for previous and current");
+    }
+
+    for (var change in changeRecords) {
+      int addEnd = change.index + change.addedCount;
+      int removeEnd = change.index + change.removed.length;
+
+      var addedItems = current.getRange(change.index, addEnd);
+      previous.replaceRange(change.index, removeEnd, addedItems);
+    }
+  }
 }
diff --git a/pkg/observe/lib/src/observer_transform.dart b/pkg/observe/lib/src/observer_transform.dart
new file mode 100644
index 0000000..0587cd9
--- /dev/null
+++ b/pkg/observe/lib/src/observer_transform.dart
@@ -0,0 +1,83 @@
+// 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.
+
+library observe.src.observer_transform;
+
+import 'package:observe/observe.dart';
+
+/// ObserverTransform is used to dynamically transform observed value(s).
+///
+///    var obj = new ObservableBox(10);
+///    var observer = new PathObserver(obj, 'value');
+///    var transform = new ObserverTransform(observer,
+///        (x) => x * 2, setValue: (x) => x ~/ 2);
+///
+///    // Open returns the current value of 20.
+///    transform.open((newValue) => print('new: $newValue'));
+///
+///    obj.value = 20; // prints 'new: 40' async
+///    new Future(() {
+///      transform.value = 4; // obj.value will be 2
+///    });
+///
+/// ObserverTransform can also be used to reduce a set of observed values to a
+/// single value:
+///
+///    var obj = new ObservableMap.from({'a': 1, 'b': 2, 'c': 3});
+///    var observer = new CompoundObserver()
+///      ..addPath(obj, 'a')
+///      ..addPath(obj, 'b')
+///      ..addPath(obj, 'c');
+///
+///    var transform = new ObserverTransform(observer,
+///        (values) => values.fold(0, (x, y) => x + y));
+///
+///    // Open returns the current value of 6.
+///    transform.open((newValue) => print('new: $newValue'));
+///
+///    obj['a'] = 2;
+///    obj['c'] = 10; // will print 'new 14' asynchronously
+///
+class ObserverTransform extends Bindable {
+  Bindable _bindable;
+  Function _getTransformer, _setTransformer;
+  Function _notifyCallback;
+  var _value;
+
+  ObserverTransform(Bindable bindable, computeValue(value), {setValue(value)})
+      : _bindable = bindable,
+        _getTransformer = computeValue,
+        _setTransformer = setValue;
+
+  open(callback(value)) {
+    _notifyCallback = callback;
+    _value = _getTransformer(_bindable.open(_observedCallback));
+    return _value;
+  }
+
+  _observedCallback(newValue) {
+    final value = _getTransformer(newValue);
+    if (value == _value) return null;
+    _value = value;
+    return _notifyCallback(value);
+  }
+
+  void close() {
+    if (_bindable != null) _bindable.close();
+    _bindable = null;
+    _getTransformer = null;
+    _setTransformer = null;
+    _notifyCallback = null;
+    _value = null;
+  }
+
+  get value => _value = _getTransformer(_bindable.value);
+
+  set value(newValue) {
+    if (_setTransformer != null) {
+      newValue = _setTransformer(newValue);
+    }
+    _bindable.value = newValue;
+  }
+}
diff --git a/pkg/observe/lib/src/path_observer.dart b/pkg/observe/lib/src/path_observer.dart
index 5e59b80..8054a3a 100644
--- a/pkg/observe/lib/src/path_observer.dart
+++ b/pkg/observe/lib/src/path_observer.dart
@@ -5,6 +5,8 @@
 library observe.src.path_observer;
 
 import 'dart:async';
+import 'dart:collection';
+import 'dart:math' show min;
 @MirrorsUsed(metaTargets: const [Reflectable, ObservableProperty],
     override: 'observe.src.path_observer')
 import 'dart:mirrors';
@@ -12,209 +14,216 @@
 import 'package:observe/observe.dart';
 import 'package:observe/src/observable.dart' show objectType;
 
-// This code is inspired by ChangeSummary:
-// https://github.com/rafaelw/ChangeSummary/blob/master/change_summary.js
-// ...which underlies MDV. Since we don't need the functionality of
-// ChangeSummary, we just implement what we need for data bindings.
-// This allows our implementation to be much simpler.
+/// A data-bound path starting from a view-model or model object, for example
+/// `foo.bar.baz`.
+///
+/// When [open] is called, this will observe changes to the object and any
+/// intermediate object along the path, and send updated values accordingly.
+/// When [close] is called it will stop observing the objects.
+///
+/// This class is used to implement `Node.bind` and similar functionality in
+/// the [template_binding](pub.dartlang.org/packages/template_binding) package.
+class PathObserver extends _Observer implements Bindable {
+  PropertyPath _path;
+  Object _object;
+  _ObservedSet _directObserver;
 
-/**
- * A data-bound path starting from a view-model or model object, for example
- * `foo.bar.baz`.
- *
- * When the [values] stream is being listened to, this will observe changes to
- * the object and any intermediate object along the path, and send [values]
- * accordingly. When all listeners are unregistered it will stop observing
- * the objects.
- *
- * This class is used to implement [Node.bind] and similar functionality.
- */
+  /// Observes [path] on [object] for changes. This returns an object
+  /// that can be used to get the changes and get/set the value at this path.
+  ///
+  /// The path can be a [PropertyPath], or a [String] used to construct it.
+  ///
+  /// See [open] and [value].
+  PathObserver(Object object, [path])
+      : _object = object,
+        _path = path is PropertyPath ? path : new PropertyPath(path);
+
+  bool get _isClosed => _path == null;
+
+  /// Sets the value at this path.
+  @reflectable void set value(Object newValue) {
+    if (_path != null) _path.setValueFrom(_object, newValue);
+  }
+
+  int get _reportArgumentCount => 2;
+
+  /// Initiates observation and returns the initial value.
+  /// The callback will be passed the updated [value], and may optionally be
+  /// declared to take a second argument, which will contain the previous value.
+  open(callback) => super.open(callback);
+
+  void _connect() {
+    _directObserver = new _ObservedSet(this, _object);
+    _check(skipChanges: true);
+  }
+
+  void _disconnect() {
+    _value = null;
+    if (_directObserver != null) {
+      _directObserver.close(this);
+      _directObserver = null;
+    }
+    // Dart note: the JS impl does not do this, but it seems consistent with
+    // CompoundObserver. After closing the PathObserver can't be reopened.
+    _path = null;
+    _object = null;
+  }
+
+  void _iterateObjects(void observe(obj)) {
+    _path._iterateObjects(_object, observe);
+  }
+
+  bool _check({bool skipChanges: false}) {
+    var oldValue = _value;
+    _value = _path.getValueFrom(_object);
+    if (skipChanges || _value == oldValue) return false;
+
+    _report(_value, oldValue);
+    return true;
+  }
+}
+
+/// A dot-delimieted property path such as "foo.bar" or "foo.10.bar".
+/// The path specifies how to get a particular value from an object graph, where
+/// the graph can include arrays.
 // TODO(jmesserly): consider specialized subclasses for:
 // * empty path
 // * "value"
 // * single token in path, e.g. "foo"
-class PathObserver extends ChangeNotifier {
-  /** The path string. */
-  final String path;
-
-  /** True if the path is valid, otherwise false. */
-  final bool _isValid;
-
+class PropertyPath {
+  /// The segments of the path.
   final List<Object> _segments;
-  List<Object> _values;
-  List<StreamSubscription> _subs;
 
-  final Function _computeValue;
-
-  /**
-   * Observes [path] on [object] for changes. This returns an object that can be
-   * used to get the changes and get/set the value at this path.
-   *
-   * You can optionally use [computeValue] to apply a function to the result of
-   * evaluating the path. The function should be pure, as PathObserver will not
-   * know to observe any of its dependencies. If you need to observe mutliple
-   * values, use [CompoundPathObserver] instead.
-   *
-   * See [PathObserver.bindSync] and [PathObserver.value].
-   */
-  PathObserver(Object object, String path, {computeValue(newValue)})
-      : path = path,
-        _computeValue = computeValue,
-        _isValid = _isPathValid(path),
-        _segments = <Object>[] {
-
-    if (_isValid) {
-      for (var segment in path.trim().split('.')) {
-        if (segment == '') continue;
-        var index = int.parse(segment, radix: 10, onError: (_) => null);
-        _segments.add(index != null ? index : new Symbol(segment));
-      }
-    }
-
-    // Initialize arrays.
-    // Note that the path itself can't change after it is initially
-    // constructed, even though the objects along the path can change.
-    _values = new List<Object>(_segments.length + 1);
-
-    // If we have an empty path, we need to apply the transformation function
-    // to the value. The "value" property should always show the transformed
-    // value.
-    if (_segments.isEmpty && computeValue != null) {
-      object = computeValue(object);
-    }
-
-    _values[0] = object;
-    _subs = new List<StreamSubscription>(_segments.length);
-  }
-
-  /** The object being observed. If the path is empty this will be [value]. */
-  get object => _values[0];
-
-  /** Gets the last reported value at this path. */
-  @reflectable get value {
-    if (!_isValid) return null;
-    if (!hasObservers) _updateValues();
-    return _values.last;
-  }
-
-  /** Sets the value at this path. */
-  @reflectable void set value(Object newValue) {
-    int len = _segments.length;
-
-    // TODO(jmesserly): throw if property cannot be set?
-    // MDV seems tolerant of these errors.
-    if (len == 0) return;
-    if (!hasObservers) _updateValues(end: len - 1);
-
-    if (_setObjectProperty(_values[len - 1], _segments[len - 1], newValue)) {
-      // Technically, this would get updated asynchronously via a change record.
-      // However, it is nice if calling the getter will yield the same value
-      // that was just set. So we use this opportunity to update our cache.
-      _values[len] = newValue;
-    }
-  }
-
-  /**
-   * Invokes the [callback] immediately with the current [value], and every time
-   * the value changes. This is useful for bindings, which want to be up-to-date
-   * immediately and stay bound to the value of the path.
-   */
-  StreamSubscription bindSync(void callback(value)) {
-    var result = changes.listen((records) { callback(value); });
-    callback(value);
-    return result;
-  }
-
-  void observed() {
-    super.observed();
-    _updateValues();
-    _observePath();
-  }
-
-  void unobserved() {
-    for (int i = 0; i < _subs.length; i++) {
-      if (_subs[i] != null) {
-        _subs[i].cancel();
-        _subs[i] = null;
-      }
-    }
-    super.unobserved();
-  }
-
-  // TODO(jmesserly): should we be caching these values if not observing?
-  void _updateValues({int end}) {
-    if (end == null) end = _segments.length;
-    int last = _segments.length - 1;
-    for (int i = 0; i < end; i++) {
-      var newValue = _getObjectProperty(_values[i], _segments[i]);
-      if (i == last && _computeValue != null) {
-        newValue = _computeValue(newValue);
-      }
-      _values[i + 1] = newValue;
-    }
-  }
-
-  void _updateObservedValues({int start: 0}) {
-    var oldValue, newValue;
-    for (int i = start, last = _segments.length - 1; i <= last; i++) {
-      oldValue = _values[i + 1];
-      newValue = _getObjectProperty(_values[i], _segments[i]);
-      if (i == last && _computeValue != null) {
-        newValue = _computeValue(newValue);
-      }
-      if (identical(oldValue, newValue)) {
-        _observePath(start, i);
-        return;
-      }
-      _values[i + 1] = newValue;
-    }
-
-    _observePath(start);
-    notifyPropertyChange(#value, oldValue, newValue);
-  }
-
-  void _observePath([int start = 0, int end]) {
-    if (end == null) end = _segments.length;
-
-    for (int i = start; i < end; i++) {
-      if (_subs[i] != null) _subs[i].cancel();
-      _observeIndex(i);
-    }
-  }
-
-  void _observeIndex(int i) {
-    final object = _values[i];
-    final segment = _segments[i];
-    if (segment is int) {
-      if (object is ObservableList) {
-        _subs[i] = object.listChanges.listen((List<ListChangeRecord> records) {
-          for (var record in records) {
-            if (record.indexChanged(segment)) {
-              _updateObservedValues(start: i);
-              return;
-            }
-          }
-        });
-      }
-    } else if (object is Observable) {
-      // TODO(jmesserly): rather than allocating a new closure for each
-      // property, we could try and have one for the entire path. However we'd
-      // need to do a linear scan to find the index as soon as we got a change.
-      // Also we need to fix ListChangeRecord and MapChangeRecord to contain
-      // the target. Not sure if it's worth it.
-
-      _subs[i] = object.changes.listen((List<ChangeRecord> records) {
-        for (var record in records) {
-          if (_changeRecordMatches(record, segment)) {
-            _updateObservedValues(start: i);
-            return;
-          }
+  /// Creates a new [PropertyPath]. These can be stored to avoid excessive
+  /// parsing of path strings.
+  ///
+  /// The provided [path] should be a String or a List. If it is a list it
+  /// should contain only Symbols and integers. This can be used to avoid
+  /// parsing.
+  ///
+  /// Note that this constructor will canonicalize identical paths in some cases
+  /// to save memory, but this is not guaranteed. Use [==] for comparions
+  /// purposes instead of [identical].
+  factory PropertyPath([path]) {
+    if (path is List) {
+      var copy = new List.from(path, growable: false);
+      for (var segment in copy) {
+        if (segment is! int && segment is! Symbol) {
+          throw new ArgumentError('List must contain only ints and Symbols');
         }
-      });
+      }
+      return new PropertyPath._(copy);
+    }
+
+    if (path == null) path = '';
+
+    var pathObj = _pathCache[path];
+    if (pathObj != null) return pathObj;
+
+    if (!_isPathValid(path)) return _InvalidPropertyPath._instance;
+
+    final segments = [];
+    for (var segment in path.trim().split('.')) {
+      if (segment == '') continue;
+      var index = int.parse(segment, radix: 10, onError: (_) => null);
+      segments.add(index != null ? index : new Symbol(segment));
+    }
+
+    // TODO(jmesserly): we could use an UnmodifiableListView here, but that adds
+    // memory overhead.
+    pathObj = new PropertyPath._(segments.toList(growable: false));
+    if (_pathCache.length >= _pathCacheLimit) {
+      _pathCache.remove(_pathCache.keys.first);
+    }
+    _pathCache[path] = pathObj;
+    return pathObj;
+  }
+
+  PropertyPath._(this._segments);
+
+  int get length => _segments.length;
+  bool get isEmpty => _segments.isEmpty;
+  bool get isValid => true;
+
+  String toString() {
+    if (!isValid) return '<invalid path>';
+    return _segments
+        .map((s) => s is Symbol ? MirrorSystem.getName(s) : s)
+        .join('.');
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! PropertyPath) return false;
+    if (isValid != other.isValid) return false;
+
+    int len = _segments.length;
+    if (len != other._segments.length) return false;
+    for (int i = 0; i < len; i++) {
+      if (_segments[i] != other._segments[i]) return false;
+    }
+    return true;
+  }
+
+  /// This is the [Jenkins hash function][1] but using masking to keep
+  /// values in SMI range.
+  /// [1]: http://en.wikipedia.org/wiki/Jenkins_hash_function
+  // TODO(jmesserly): should reuse this instead, see
+  // https://code.google.com/p/dart/issues/detail?id=11617
+  int get hashCode {
+    int hash = 0;
+    for (int i = 0, len = _segments.length; i < len; i++) {
+      hash = 0x1fffffff & (hash + _segments[i].hashCode);
+      hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+      hash = hash ^ (hash >> 6);
+    }
+    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) <<  3));
+    hash = hash ^ (hash >> 11);
+    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+  }
+
+  /// Returns the current of the path from the provided [obj]ect.
+  getValueFrom(Object obj) {
+    if (!isValid) return null;
+    for (var segment in _segments) {
+      if (obj == null) return null;
+      obj = _getObjectProperty(obj, segment);
+    }
+    return obj;
+  }
+
+  /// Attempts to set the [value] of the path from the provided [obj]ect.
+  /// Returns true if and only if the path was reachable and set.
+  bool setValueFrom(Object obj, Object value) {
+    var end = _segments.length - 1;
+    if (end < 0) return false;
+    for (int i = 0; i < end; i++) {
+      if (obj == null) return false;
+      obj = _getObjectProperty(obj, _segments[i]);
+    }
+    return _setObjectProperty(obj, _segments[end], value);
+  }
+
+  void _iterateObjects(Object obj, void observe(obj)) {
+    if (!isValid || isEmpty) return;
+
+    int i = 0, last = _segments.length - 1;
+    while (obj != null) {
+      observe(obj);
+
+      if (i >= last) break;
+      obj = _getObjectProperty(obj, _segments[i++]);
     }
   }
 }
 
+class _InvalidPropertyPath extends PropertyPath {
+  static final _instance = new _InvalidPropertyPath();
+
+  bool get isValid => false;
+  _InvalidPropertyPath() : super._([]);
+}
+
 bool _changeRecordMatches(record, key) {
   if (record is PropertyChangeRecord) {
     return (record as PropertyChangeRecord).name == key;
@@ -318,10 +327,8 @@
   return false;
 }
 
-/**
- * True if the type has a method, other than on Object.
- * Doesn't consider noSuchMethod, unless [name] is `#noSuchMethod`.
- */
+/// True if the type has a method, other than on Object.
+/// Doesn't consider noSuchMethod, unless [name] is `#noSuchMethod`.
 bool _hasMethod(ClassMirror type, Symbol name) {
   while (type != objectType) {
     final member = type.declarations[name];
@@ -356,14 +363,376 @@
   return new RegExp('^$path\$');
 }();
 
-final _spacesRegExp = new RegExp(r'\s');
-
 bool _isPathValid(String s) {
-  s = s.replaceAll(_spacesRegExp, '');
-
+  s = s.trim();
   if (s == '') return true;
   if (s[0] == '.') return false;
   return _pathRegExp.hasMatch(s);
 }
 
 final Logger _logger = new Logger('observe.PathObserver');
+
+
+/// This is a simple cache. It's like LRU but we don't update an item on a
+/// cache hit, because that would require allocation. Better to let it expire
+/// and reallocate the PropertyPath.
+// TODO(jmesserly): this optimization is from observe-js, how valuable is it in
+// practice?
+final _pathCache = new LinkedHashMap<String, PropertyPath>();
+
+/// The size of a path like "foo.bar" is approximately 160 bytes, so this
+/// reserves ~16Kb of memory for recently used paths. Since paths are frequently
+/// reused, the theory is that this ends up being a good tradeoff in practice.
+// (Note: the 160 byte estimate is from Dart VM 1.0.0.10_r30798 on x64 without
+// using UnmodifiableListView in PropertyPath)
+const int _pathCacheLimit = 100;
+
+/// [CompoundObserver] is a [Bindable] object which knows how to listen to
+/// multiple values (registered via [addPath] or [addObserver]) and invoke a
+/// callback when one or more of the values have changed.
+///
+///    var obj = new ObservableMap.from({'a': 1, 'b': 2});
+///    var otherObj = new ObservableMap.from({'c': 3});
+///
+///    var observer = new CompoundObserver()
+///      ..addPath(obj, 'a');
+///      ..addObserver(new PathObserver(obj, 'b'));
+///      ..addPath(otherObj, 'c');
+///      ..open((values) {
+///        for (int i = 0; i < values.length; i++) {
+///          print('The value at index $i is now ${values[i]}');
+///        }
+///      });
+///
+///   obj['a'] = 10; // print will be triggered async
+///
+class CompoundObserver extends _Observer implements Bindable {
+  _ObservedSet _directObserver;
+  List _observed = [];
+
+  bool get _isClosed => _observed == null;
+
+  CompoundObserver() {
+    _value = [];
+  }
+
+  int get _reportArgumentCount => 3;
+
+  /// Initiates observation and returns the initial value.
+  /// The callback will be passed the updated [value], and may optionally be
+  /// declared to take a second argument, which will contain the previous value.
+  ///
+  /// Implementation note: a third argument can also be declared, which will
+  /// receive a list of objects and paths, such that `list[2 * i]` will access
+  /// the object and `list[2 * i + 1]` will access the path, where `i` is the
+  /// order of the [addPath] call. This parameter is only used by
+  /// `package:polymer` as a performance optimization, and should not be relied
+  /// on in new code.
+  open(callback) => super.open(callback);
+
+  void _connect() {
+    _check(skipChanges: true);
+
+    for (var i = 0; i < _observed.length; i += 2) {
+      var object = _observed[i];
+      if (!identical(object, _observerSentinel)) {
+        _directObserver = new _ObservedSet(this, object);
+        break;
+      }
+    }
+  }
+
+  void _disconnect() {
+    _value = null;
+
+    if (_directObserver != null) {
+      _directObserver.close(this);
+      _directObserver = null;
+    }
+
+    for (var i = 0; i < _observed.length; i += 2) {
+      if (identical(_observed[i], _observerSentinel)) {
+        _observed[i + 1].close();
+      }
+    }
+    _observed = null;
+  }
+
+  /// Adds a dependency on the property [path] accessed from [object].
+  /// [path] can be a [PropertyPath] or a [String]. If it is omitted an empty
+  /// path will be used.
+  void addPath(Object object, [path]) {
+    if (_isOpen || _isClosed) {
+      throw new StateError('Cannot add paths once started.');
+    }
+
+    if (path is! PropertyPath) path = new PropertyPath(path);
+    _observed..add(object)..add(path);
+  }
+
+  void addObserver(Bindable observer) {
+    if (_isOpen || _isClosed) {
+      throw new StateError('Cannot add observers once started.');
+    }
+
+    observer.open(_deliver);
+    _observed..add(_observerSentinel)..add(observer);
+  }
+
+  void _iterateObjects(void observe(obj)) {
+    for (var i = 0; i < _observed.length; i += 2) {
+      var object = _observed[i];
+      if (!identical(object, _observerSentinel)) {
+        (_observed[i + 1] as PropertyPath)._iterateObjects(object, observe);
+      }
+    }
+  }
+
+  bool _check({bool skipChanges: false}) {
+    bool changed = false;
+    _value.length = _observed.length ~/ 2;
+    var oldValues = null;
+    for (var i = 0; i < _observed.length; i += 2) {
+      var pathOrObserver = _observed[i + 1];
+      var object = _observed[i];
+      var value = identical(object, _observerSentinel) ?
+          (pathOrObserver as Bindable).value :
+          (pathOrObserver as PropertyPath).getValueFrom(object);
+
+      if (skipChanges) {
+        _value[i ~/ 2] = value;
+        continue;
+      }
+
+      if (value == _value[i ~/ 2]) continue;
+
+      // don't allocate this unless necessary.
+      if (_notifyArgumentCount >= 2) {
+        if (oldValues == null) oldValues = new Map();
+        oldValues[i ~/ 2] = _value[i ~/ 2];
+      }
+
+      changed = true;
+      _value[i ~/ 2] = value;
+    }
+
+    if (!changed) return false;
+
+    // TODO(rafaelw): Having _observed as the third callback arg here is
+    // pretty lame API. Fix.
+    _report(_value, oldValues, _observed);
+    return true;
+  }
+}
+
+const _observerSentinel = const _ObserverSentinel();
+class _ObserverSentinel { const _ObserverSentinel(); }
+
+// A base class for the shared API implemented by PathObserver and
+// CompoundObserver and used in _ObservedSet.
+abstract class _Observer extends Bindable {
+  static int _nextBirthId = 0;
+
+  /// A number indicating when the object was created.
+  final int _birthId = _nextBirthId++;
+
+  Function _notifyCallback;
+  int _notifyArgumentCount;
+  var _value;
+
+  // abstract members
+  void _iterateObjects(void observe(obj));
+  void _connect();
+  void _disconnect();
+  bool get _isClosed;
+  _check({bool skipChanges: false});
+
+  bool get _isOpen => _notifyCallback != null;
+
+  /// The number of arguments the subclass will pass to [_report].
+  int get _reportArgumentCount;
+
+  open(callback) {
+    if (_isOpen || _isClosed) {
+      throw new StateError('Observer has already been opened.');
+    }
+
+    if (_minArgumentCount(callback) > _reportArgumentCount) {
+      throw new ArgumentError('callback should take $_reportArgumentCount or '
+          'fewer arguments');
+    }
+
+    _notifyCallback = callback;
+    _notifyArgumentCount = min(_reportArgumentCount,
+        _maxArgumentCount(callback));
+
+    _connect();
+    return _value;
+  }
+
+  @reflectable get value {
+    _check(skipChanges: true);
+    return _value;
+  }
+
+  void close() {
+    if (!_isOpen) return;
+
+    _disconnect();
+    _value = null;
+    _notifyCallback = null;
+  }
+
+  void _deliver(_) {
+    if (_isOpen) _dirtyCheck();
+  }
+
+  bool _dirtyCheck() {
+    var cycles = 0;
+    while (cycles < _MAX_DIRTY_CHECK_CYCLES && _check()) {
+      cycles++;
+    }
+    return cycles > 0;
+  }
+
+  void _report(newValue, oldValue, [extraArg]) {
+    try {
+      switch (_notifyArgumentCount) {
+        case 0: _notifyCallback(); break;
+        case 1: _notifyCallback(newValue); break;
+        case 2: _notifyCallback(newValue, oldValue); break;
+        case 3: _notifyCallback(newValue, oldValue, extraArg); break;
+      }
+    } catch (e, s) {
+      // Deliver errors async, so if a single callback fails it doesn't prevent
+      // other things from working.
+      new Completer().completeError(e, s);
+    }
+  }
+}
+
+typedef _Func0();
+typedef _Func1(a);
+typedef _Func2(a, b);
+typedef _Func3(a, b, c);
+
+int _minArgumentCount(fn) {
+  if (fn is _Func0) return 0;
+  if (fn is _Func1) return 1;
+  if (fn is _Func2) return 2;
+  if (fn is _Func3) return 3;
+  return 4; // at least 4 arguments are required.
+}
+
+int _maxArgumentCount(fn) {
+  if (fn is _Func3) return 3;
+  if (fn is _Func2) return 2;
+  if (fn is _Func1) return 1;
+  if (fn is _Func0) return 0;
+  return -1;
+}
+
+class _ObservedSet {
+  /// To prevent sequential [PathObserver]s and [CompoundObserver]s from
+  /// observing the same object, we check if they are observing the same root
+  /// as the most recently created observer, and if so merge it into the
+  /// existing _ObservedSet.
+  ///
+  /// See <https://github.com/Polymer/observe-js/commit/f0990b1> and
+  /// <https://codereview.appspot.com/46780044/>.
+  static _ObservedSet _lastSet;
+
+  /// The root object for a [PathObserver]. For a [CompoundObserver], the root
+  /// object of the first path observed. This is used by the constructor to
+  /// reuse an [_ObservedSet] that starts from the same object.
+  Object _rootObject;
+
+  /// Observers associated with this root object, in birth order.
+  final Map<int, _Observer> _observers = new SplayTreeMap();
+
+  // Dart note: the JS implementation is O(N^2) because Array.indexOf is used
+  // for lookup in these two arrays. We use HashMap to avoid this problem. It
+  // also gives us a nice way of tracking the StreamSubscription.
+  Map<Object, StreamSubscription> _objects;
+  Map<Object, StreamSubscription> _toRemove;
+
+  bool _resetNeeded = false;
+
+  factory _ObservedSet(_Observer observer, Object rootObj) {
+    if (_lastSet == null || !identical(_lastSet._rootObject, rootObj)) {
+      _lastSet = new _ObservedSet._(rootObj);
+    }
+    _lastSet.open(observer);
+  }
+
+  _ObservedSet._(this._rootObject);
+
+  void open(_Observer obs) {
+    _observers[obs._birthId] = obs;
+    obs._iterateObjects(observe);
+  }
+
+  void close(_Observer obs) {
+    var anyLeft = false;
+
+    _observers.remove(obs._birthId);
+
+    if (_observers.isNotEmpty) {
+      _resetNeeded = true;
+      scheduleMicrotask(reset);
+      return;
+    }
+    _resetNeeded = false;
+
+    if (_objects != null) {
+      for (var sub in _objects) sub.cancel();
+      _objects = null;
+    }
+  }
+
+  void observe(Object obj) {
+    if (obj is ObservableList) _observeStream(obj.listChanges);
+    if (obj is Observable) _observeStream(obj.changes);
+  }
+
+  void _observeStream(Stream stream) {
+    // TODO(jmesserly): we hash on streams as we have two separate change
+    // streams for ObservableList. Not sure if that is the design we will use
+    // going forward.
+
+    if (_objects == null) _objects = new HashMap();
+    StreamSubscription sub = null;
+    if (_toRemove != null) sub = _toRemove.remove(stream);
+    if (sub != null) {
+      _objects[stream] = sub;
+    } else if (!_objects.containsKey(stream)) {
+      _objects[stream] = stream.listen(_callback);
+    }
+  }
+
+  void reset() {
+    if (!_resetNeeded) return;
+
+    var objs = _toRemove == null ? new HashMap() : _toRemove;
+    _toRemove = _objects;
+    _objects = objs;
+    for (var observer in _observers.values) {
+      if (observer._isOpen) observer._iterateObjects(observe);
+    }
+
+    for (var sub in _toRemove.values) sub.cancel();
+
+    _toRemove = null;
+  }
+
+  void _callback(records) {
+    for (var observer in _observers.values.toList(growable: false)) {
+      if (observer._isOpen) observer._check();
+    }
+
+    _resetNeeded = true;
+    scheduleMicrotask(reset);
+  }
+}
+
+const int _MAX_DIRTY_CHECK_CYCLES = 1000;
diff --git a/pkg/observe/lib/transformer.dart b/pkg/observe/lib/transformer.dart
index 7e29672..035cff5 100644
--- a/pkg/observe/lib/transformer.dart
+++ b/pkg/observe/lib/transformer.dart
@@ -10,7 +10,6 @@
 
 import 'dart:async';
 
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
@@ -116,7 +115,7 @@
 /** Parse [code] using analyzer. */
 CompilationUnit _parseCompilationUnit(String code) {
   var errorListener = new _ErrorCollector();
-  var reader = new CharSequenceReader(new CharSequence(code));
+  var reader = new CharSequenceReader(code);
   var scanner = new Scanner(null, reader, errorListener);
   var token = scanner.tokenize();
   var parser = new Parser(null, errorListener);
diff --git a/pkg/observe/pubspec.yaml b/pkg/observe/pubspec.yaml
index 87c8727..3b0407c 100644
--- a/pkg/observe/pubspec.yaml
+++ b/pkg/observe/pubspec.yaml
@@ -1,5 +1,5 @@
 name: observe
-version: 0.9.3
+version: 0.10.0-dev
 author: Polymer.dart Authors <web-ui-dev@dartlang.org>
 description: >
   Observable properties and objects for use in Model-Driven-Views (MDV).
diff --git a/pkg/observe/test/list_change_test.dart b/pkg/observe/test/list_change_test.dart
index 6aeac7c..30afb60 100644
--- a/pkg/observe/test/list_change_test.dart
+++ b/pkg/observe/test/list_change_test.dart
@@ -10,10 +10,7 @@
 // This file contains code ported from:
 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js
 
-main() {
-  // TODO(jmesserly): rename this? Is summarizeListChanges coming back?
-  group('summarizeListChanges', listChangeTests);
-}
+main() => dirtyCheckZone().run(listChangeTests);
 
 // TODO(jmesserly): port or write array fuzzer tests
 listChangeTests() {
@@ -27,7 +24,7 @@
 
   _delta(i, r, a) => new ListChangeRecord(model, i, removed: r, addedCount: a);
 
-  observeTest('sequential adds', () {
+  test('sequential adds', () {
     model = toObservable([]);
     model.add(0);
 
@@ -38,12 +35,10 @@
     model.add(2);
 
     expect(summary, null);
-    performMicrotaskCheckpoint();
-
-    expectChanges(summary, [_delta(1, [], 2)]);
+    return new Future(() => expectChanges(summary, [_delta(1, [], 2)]));
   });
 
-  observeTest('List Splice Truncate And Expand With Length', () {
+  test('List Splice Truncate And Expand With Length', () {
     model = toObservable(['a', 'b', 'c', 'd', 'e']);
 
     var summary;
@@ -51,28 +46,20 @@
 
     model.length = 2;
 
-    performMicrotaskCheckpoint();
-    expectChanges(summary, [_delta(2, ['c', 'd', 'e'], 0)]);
-    summary = null;
+    return new Future(() {
+      expectChanges(summary, [_delta(2, ['c', 'd', 'e'], 0)]);
+      summary = null;
+      model.length = 5;
 
-    model.length = 5;
+    }).then(newMicrotask).then((_) {
 
-    performMicrotaskCheckpoint();
-    expectChanges(summary, [_delta(2, [], 3)]);
+      expectChanges(summary, [_delta(2, [], 3)]);
+    });
   });
 
   group('List deltas can be applied', () {
 
-    var summary = null;
-
-    observeArray(model) {
-      sub = model.listChanges.listen((r) { summary = r; });
-    }
-
-    applyAndCheckDeltas(model, copy) {
-      summary = null;
-      performMicrotaskCheckpoint();
-
+    applyAndCheckDeltas(model, copy, changes) => changes.then((summary) {
       // apply deltas to the copy
       for (var delta in summary) {
         copy.removeRange(delta.index, delta.index + delta.removed.length);
@@ -83,75 +70,75 @@
 
       // Note: compare strings for easier debugging.
       expect('$copy', '$model', reason: 'summary $summary');
-    }
+    });
 
-    observeTest('Contained', () {
+    test('Contained', () {
       var model = toObservable(['a', 'b']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeAt(1);
       model.insertAll(0, ['c', 'd', 'e']);
       model.removeRange(1, 3);
       model.insert(1, 'f');
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Delete Empty', () {
+    test('Delete Empty', () {
       var model = toObservable([1]);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeAt(0);
       model.insertAll(0, ['a', 'b', 'c']);
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Right Non Overlap', () {
+    test('Right Non Overlap', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeRange(0, 1);
       model.insert(0, 'e');
       model.removeRange(2, 3);
       model.insertAll(2, ['f', 'g']);
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Left Non Overlap', () {
+    test('Left Non Overlap', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeRange(3, 4);
       model.insertAll(3, ['f', 'g']);
       model.removeRange(0, 1);
       model.insert(0, 'e');
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Right Adjacent', () {
+    test('Right Adjacent', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeRange(1, 2);
       model.insert(3, 'e');
       model.removeRange(2, 3);
       model.insertAll(0, ['f', 'g']);
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Left Adjacent', () {
+    test('Left Adjacent', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeRange(2, 4);
       model.insert(2, 'e');
@@ -159,26 +146,26 @@
       model.removeAt(1);
       model.insertAll(1, ['f', 'g']);
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Right Overlap', () {
+    test('Right Overlap', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeAt(1);
       model.insert(1, 'e');
       model.removeAt(1);
       model.insertAll(1, ['f', 'g']);
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Left Overlap', () {
+    test('Left Overlap', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeAt(2);
       model.insertAll(2, ['e', 'f', 'g']);
@@ -187,105 +174,95 @@
       model.insertAll(1, ['h', 'i', 'j']);
       // a [h i j] f g d
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Prefix And Suffix One In', () {
+    test('Prefix And Suffix One In', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.insert(0, 'z');
       model.add('z');
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Remove First', () {
+    test('Remove First', () {
       var model = toObservable([16, 15, 15]);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeAt(0);
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Update Remove', () {
+    test('Update Remove', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeAt(2);
       model.insertAll(2, ['e', 'f', 'g']);  // a b [e f g] d
       model[0] = 'h';
       model.removeAt(1);
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
 
-    observeTest('Remove Mid List', () {
+    test('Remove Mid List', () {
       var model = toObservable(['a', 'b', 'c', 'd']);
       var copy = model.toList();
-      observeArray(model);
+      var changes = model.listChanges.first;
 
       model.removeAt(2);
 
-      applyAndCheckDeltas(model, copy);
+      return applyAndCheckDeltas(model, copy, changes);
     });
   });
 
   group('edit distance', () {
-    var summary = null;
 
-    observeArray(model) {
-      sub = model.listChanges.listen((r) { summary = r; });
-    }
-
-    assertEditDistance(orig, expectDistance) {
-      summary = null;
-      performMicrotaskCheckpoint();
+    assertEditDistance(orig, changes, expectedDist) => changes.then((summary) {
       var actualDistance = 0;
-
-      if (summary != null) {
-        for (var delta in summary) {
-          actualDistance += delta.addedCount + delta.removed.length;
-        }
+      for (var delta in summary) {
+        actualDistance += delta.addedCount + delta.removed.length;
       }
 
-      expect(actualDistance, expectDistance);
-    }
-
-    observeTest('add items', () {
-      var model = toObservable([]);
-      observeArray(model);
-      model.addAll([1, 2, 3]);
-      assertEditDistance(model, 3);
+      expect(actualDistance, expectedDist);
     });
 
-    observeTest('trunacte and add, sharing a contiguous block', () {
+    test('add items', () {
+      var model = toObservable([]);
+      var changes = model.listChanges.first;
+      model.addAll([1, 2, 3]);
+      return assertEditDistance(model, changes, 3);
+    });
+
+    test('trunacte and add, sharing a contiguous block', () {
       var model = toObservable(['x', 'x', 'x', 'x', '1', '2', '3']);
-      observeArray(model);
+      var changes = model.listChanges.first;
       model.length = 0;
       model.addAll(['1', '2', '3', 'y', 'y', 'y', 'y']);
-      assertEditDistance(model, 8);
+      return assertEditDistance(model, changes, 8);
     });
 
-    observeTest('truncate and add, sharing a discontiguous block', () {
+    test('truncate and add, sharing a discontiguous block', () {
       var model = toObservable(['1', '2', '3', '4', '5']);
-      observeArray(model);
+      var changes = model.listChanges.first;
       model.length = 0;
       model.addAll(['a', '2', 'y', 'y', '4', '5', 'z', 'z']);
-      assertEditDistance(model, 7);
+      return assertEditDistance(model, changes, 7);
     });
 
-    observeTest('insert at beginning and end', () {
+    test('insert at beginning and end', () {
       var model = toObservable([2, 3, 4]);
-      observeArray(model);
+      var changes = model.listChanges.first;
       model.insert(0, 5);
       model[2] = 6;
       model.add(7);
-      assertEditDistance(model, 4);
+      return assertEditDistance(model, changes, 4);
     });
   });
 }
diff --git a/pkg/observe/test/observable_list_test.dart b/pkg/observe/test/observable_list_test.dart
index 66a03d3..81ca45f 100644
--- a/pkg/observe/test/observable_list_test.dart
+++ b/pkg/observe/test/observable_list_test.dart
@@ -7,7 +7,9 @@
 import 'package:unittest/unittest.dart';
 import 'observe_test_utils.dart';
 
-main() {
+main() => dirtyCheckZone().run(_runTests);
+
+_runTests() {
   // TODO(jmesserly): need all standard List API tests.
 
   StreamSubscription sub, sub2;
@@ -36,48 +38,54 @@
 
     tearDown(sharedTearDown);
 
-    observeTest('add changes length', () {
+    test('add changes length', () {
       list.add(4);
       expect(list, [1, 2, 3, 4]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_lengthChange(3, 4)]);
+      return new Future(() {
+        expectChanges(changes, [_lengthChange(3, 4)]);
+      });
     });
 
-    observeTest('removeObject', () {
+    test('removeObject', () {
       list.remove(2);
       expect(list, orderedEquals([1, 3]));
 
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_lengthChange(3, 2)]);
+      return new Future(() {
+        expectChanges(changes, [_lengthChange(3, 2)]);
+      });
     });
 
-    observeTest('removeRange changes length', () {
+    test('removeRange changes length', () {
       list.add(4);
       list.removeRange(1, 3);
       expect(list, [1, 4]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_lengthChange(3, 4), _lengthChange(4, 2)]);
+      return new Future(() {
+        expectChanges(changes, [_lengthChange(3, 4), _lengthChange(4, 2)]);
+      });
     });
 
-    observeTest('length= changes length', () {
+    test('length= changes length', () {
       list.length = 5;
       expect(list, [1, 2, 3, null, null]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_lengthChange(3, 5)]);
+      return new Future(() {
+        expectChanges(changes, [_lengthChange(3, 5)]);
+      });
     });
 
-    observeTest('[]= does not change length', () {
+    test('[]= does not change length', () {
       list[2] = 9000;
       expect(list, [1, 2, 9000]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, null);
+      return new Future(() {
+        expectChanges(changes, null);
+      });
     });
 
-    observeTest('clear changes length', () {
+    test('clear changes length', () {
       list.clear();
       expect(list, []);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_lengthChange(3, 0)]);
+      return new Future(() {
+        expectChanges(changes, [_lengthChange(3, 0)]);
+      });
     });
   });
 
@@ -94,71 +102,79 @@
 
     tearDown(sharedTearDown);
 
-    observeTest('add does not change existing items', () {
+    test('add does not change existing items', () {
       list.add(4);
       expect(list, [1, 2, 3, 4]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, []);
+      return new Future(() {
+        expectChanges(changes, []);
+      });
     });
 
-    observeTest('[]= changes item', () {
+    test('[]= changes item', () {
       list[1] = 777;
       expect(list, [1, 777, 3]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_change(1, addedCount: 1, removed: [2])]);
+      return new Future(() {
+        expectChanges(changes, [_change(1, addedCount: 1, removed: [2])]);
+      });
     });
 
-    observeTest('[]= on a different item does not fire change', () {
+    test('[]= on a different item does not fire change', () {
       list[2] = 9000;
       expect(list, [1, 2, 9000]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, []);
+      return new Future(() {
+        expectChanges(changes, []);
+      });
     });
 
-    observeTest('set multiple times results in one change', () {
+    test('set multiple times results in one change', () {
       list[1] = 777;
       list[1] = 42;
       expect(list, [1, 42, 3]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [
-        _change(1, addedCount: 1, removed: [2]),
-      ]);
+      return new Future(() {
+        expectChanges(changes, [
+          _change(1, addedCount: 1, removed: [2]),
+        ]);
+      });
     });
 
-    observeTest('set length without truncating item means no change', () {
+    test('set length without truncating item means no change', () {
       list.length = 2;
       expect(list, [1, 2]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, []);
+      return new Future(() {
+        expectChanges(changes, []);
+      });
     });
 
-    observeTest('truncate removes item', () {
+    test('truncate removes item', () {
       list.length = 1;
       expect(list, [1]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_change(1, removed: [2, 3])]);
+      return new Future(() {
+        expectChanges(changes, [_change(1, removed: [2, 3])]);
+      });
     });
 
-    observeTest('truncate and add new item', () {
+    test('truncate and add new item', () {
       list.length = 1;
       list.add(42);
       expect(list, [1, 42]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [
-        _change(1, removed: [2, 3], addedCount: 1)
-      ]);
+      return new Future(() {
+        expectChanges(changes, [
+          _change(1, removed: [2, 3], addedCount: 1)
+        ]);
+      });
     });
 
-    observeTest('truncate and add same item', () {
+    test('truncate and add same item', () {
       list.length = 1;
       list.add(2);
       expect(list, [1, 2]);
-      performMicrotaskCheckpoint();
-      expectChanges(changes, []);
+      return new Future(() {
+        expectChanges(changes, []);
+      });
     });
   });
 
-  observeTest('toString', () {
+  test('toString', () {
     var list = toObservable([1, 2, 3]);
     expect(list.toString(), '[1, 2, 3]');
   });
@@ -178,7 +194,7 @@
 
     tearDown(sharedTearDown);
 
-    observeTest('read operations', () {
+    test('read operations', () {
       expect(list.length, 6);
       expect(list[0], 1);
       expect(list.indexOf(4), 5);
@@ -189,76 +205,82 @@
       var copy = new List<int>();
       list.forEach((i) { copy.add(i); });
       expect(copy, orderedEquals([1, 2, 3, 1, 3, 4]));
-      performMicrotaskCheckpoint();
-
-      // no change from read-only operators
-      expectChanges(propRecords, null);
-      expectChanges(listRecords, null);
+      return new Future(() {
+        // no change from read-only operators
+        expectChanges(propRecords, null);
+        expectChanges(listRecords, null);
+      });
     });
 
-    observeTest('add', () {
+    test('add', () {
       list.add(5);
       list.add(6);
       expect(list, orderedEquals([1, 2, 3, 1, 3, 4, 5, 6]));
 
-      performMicrotaskCheckpoint();
-      expectChanges(propRecords, [
-        _lengthChange(6, 7),
-        _lengthChange(7, 8),
-      ]);
-      expectChanges(listRecords, [ _change(6, addedCount: 2) ]);
+      return new Future(() {
+        expectChanges(propRecords, [
+          _lengthChange(6, 7),
+          _lengthChange(7, 8),
+        ]);
+        expectChanges(listRecords, [ _change(6, addedCount: 2) ]);
+      });
     });
 
-    observeTest('[]=', () {
+    test('[]=', () {
       list[1] = list.last;
       expect(list, orderedEquals([1, 4, 3, 1, 3, 4]));
 
-      performMicrotaskCheckpoint();
-      expectChanges(propRecords, null);
-      expectChanges(listRecords, [ _change(1, addedCount: 1, removed: [2]) ]);
+      return new Future(() {
+        expectChanges(propRecords, null);
+        expectChanges(listRecords, [ _change(1, addedCount: 1, removed: [2]) ]);
+      });
     });
 
-    observeTest('removeLast', () {
+    test('removeLast', () {
       expect(list.removeLast(), 4);
       expect(list, orderedEquals([1, 2, 3, 1, 3]));
 
-      performMicrotaskCheckpoint();
-      expectChanges(propRecords, [_lengthChange(6, 5)]);
-      expectChanges(listRecords, [_change(5, removed: [4])]);
+      return new Future(() {
+        expectChanges(propRecords, [_lengthChange(6, 5)]);
+        expectChanges(listRecords, [_change(5, removed: [4])]);
+      });
     });
 
-    observeTest('removeRange', () {
+    test('removeRange', () {
       list.removeRange(1, 4);
       expect(list, orderedEquals([1, 3, 4]));
 
-      performMicrotaskCheckpoint();
-      expectChanges(propRecords, [_lengthChange(6, 3)]);
-      expectChanges(listRecords, [_change(1, removed: [2, 3, 1])]);
+      return new Future(() {
+        expectChanges(propRecords, [_lengthChange(6, 3)]);
+        expectChanges(listRecords, [_change(1, removed: [2, 3, 1])]);
+      });
     });
 
-    observeTest('sort', () {
+    test('sort', () {
       list.sort((x, y) => x - y);
       expect(list, orderedEquals([1, 1, 2, 3, 3, 4]));
 
-      performMicrotaskCheckpoint();
-      expectChanges(propRecords, null);
-      expectChanges(listRecords, [
-        _change(1, addedCount: 1),
-        _change(4, removed: [1])
-      ]);
+      return new Future(() {
+        expectChanges(propRecords, null);
+        expectChanges(listRecords, [
+          _change(1, addedCount: 1),
+          _change(4, removed: [1])
+        ]);
+      });
     });
 
-    observeTest('clear', () {
+    test('clear', () {
       list.clear();
       expect(list, []);
 
-      performMicrotaskCheckpoint();
-      expectChanges(propRecords, [
-          _lengthChange(6, 0),
-          new PropertyChangeRecord(list, #isEmpty, false, true),
-          new PropertyChangeRecord(list, #isNotEmpty, true, false),
-      ]);
-      expectChanges(listRecords, [_change(0, removed: [1, 2, 3, 1, 3, 4])]);
+      return new Future(() {
+        expectChanges(propRecords, [
+            _lengthChange(6, 0),
+            new PropertyChangeRecord(list, #isEmpty, false, true),
+            new PropertyChangeRecord(list, #isNotEmpty, true, false),
+        ]);
+        expectChanges(listRecords, [_change(0, removed: [1, 2, 3, 1, 3, 4])]);
+      });
     });
   });
 }
diff --git a/pkg/observe/test/observable_map_test.dart b/pkg/observe/test/observable_map_test.dart
index c7ac0cf..063287e 100644
--- a/pkg/observe/test/observable_map_test.dart
+++ b/pkg/observe/test/observable_map_test.dart
@@ -7,7 +7,9 @@
 import 'package:unittest/unittest.dart';
 import 'observe_test_utils.dart';
 
-main() {
+main() => dirtyCheckZone().run(_runTests);
+
+_runTests() {
   // TODO(jmesserly): need all standard Map API tests.
 
   StreamSubscription sub;
@@ -33,50 +35,56 @@
 
     tearDown(sharedTearDown);
 
-    observeTest('add item changes length', () {
+    test('add item changes length', () {
       map['d'] = 4;
       expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_lengthChange(map, 3, 4)]);
+      return new Future(() {
+        expectChanges(changes, [_lengthChange(map, 3, 4)]);
+      });
     });
 
-    observeTest('putIfAbsent changes length', () {
+    test('putIfAbsent changes length', () {
       map.putIfAbsent('d', () => 4);
       expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_lengthChange(map, 3, 4)]);
+      return new Future(() {
+        expectChanges(changes, [_lengthChange(map, 3, 4)]);
+      });
     });
 
-    observeTest('remove changes length', () {
+    test('remove changes length', () {
       map.remove('c');
       map.remove('a');
       expect(map, {'b': 2});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [
-        _lengthChange(map, 3, 2),
-        _lengthChange(map, 2, 1)
-      ]);
+      return new Future(() {
+        expectChanges(changes, [
+          _lengthChange(map, 3, 2),
+          _lengthChange(map, 2, 1)
+        ]);
+      });
     });
 
-    observeTest('remove non-existent item does not change length', () {
+    test('remove non-existent item does not change length', () {
       map.remove('d');
       expect(map, {'a': 1, 'b': 2, 'c': 3});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, null);
+      return new Future(() {
+        expectChanges(changes, null);
+      });
     });
 
-    observeTest('set existing item does not change length', () {
+    test('set existing item does not change length', () {
       map['c'] = 9000;
       expect(map, {'a': 1, 'b': 2, 'c': 9000});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, []);
+      return new Future(() {
+        expectChanges(changes, []);
+      });
     });
 
-    observeTest('clear changes length', () {
+    test('clear changes length', () {
       map.clear();
       expect(map, {});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_lengthChange(map, 3, 0)]);
+      return new Future(() {
+        expectChanges(changes, [_lengthChange(map, 3, 0)]);
+      });
     });
   });
 
@@ -96,77 +104,86 @@
 
     tearDown(sharedTearDown);
 
-    observeTest('putIfAbsent new item does not change existing item', () {
+    test('putIfAbsent new item does not change existing item', () {
       map.putIfAbsent('d', () => 4);
       expect(map, {'a': 1, 'b': 2, 'c': 3, 'd': 4});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, []);
+      return new Future(() {
+        expectChanges(changes, []);
+      });
     });
 
-    observeTest('set item to null', () {
+    test('set item to null', () {
       map['b'] = null;
       expect(map, {'a': 1, 'b': null, 'c': 3});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_changeKey('b', 2, null)]);
+      return new Future(() {
+        expectChanges(changes, [_changeKey('b', 2, null)]);
+      });
     });
 
-    observeTest('set item to value', () {
+    test('set item to value', () {
       map['b'] = 777;
       expect(map, {'a': 1, 'b': 777, 'c': 3});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_changeKey('b', 2, 777)]);
+      return new Future(() {
+        expectChanges(changes, [_changeKey('b', 2, 777)]);
+      });
     });
 
-    observeTest('putIfAbsent does not change if already there', () {
+    test('putIfAbsent does not change if already there', () {
       map.putIfAbsent('b', () => 1234);
       expect(map, {'a': 1, 'b': 2, 'c': 3});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, null);
+      return new Future(() {
+        expectChanges(changes, null);
+      });
     });
 
-    observeTest('change a different item', () {
+    test('change a different item', () {
       map['c'] = 9000;
       expect(map, {'a': 1, 'b': 2, 'c': 9000});
-      performMicrotaskCheckpoint();
+      return new Future(() {
       expectChanges(changes, []);
+      });
     });
 
-    observeTest('change the item', () {
+    test('change the item', () {
       map['b'] = 9001;
       map['b'] = 42;
       expect(map, {'a': 1, 'b': 42, 'c': 3});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [
-        _changeKey('b', 2, 9001),
-        _changeKey('b', 9001, 42)
-      ]);
+      return new Future(() {
+        expectChanges(changes, [
+          _changeKey('b', 2, 9001),
+          _changeKey('b', 9001, 42)
+        ]);
+      });
     });
 
-    observeTest('remove other items', () {
+    test('remove other items', () {
       map.remove('a');
       expect(map, {'b': 2, 'c': 3});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, []);
+      return new Future(() {
+        expectChanges(changes, []);
+      });
     });
 
-    observeTest('remove the item', () {
+    test('remove the item', () {
       map.remove('b');
       expect(map, {'a': 1, 'c': 3});
-      performMicrotaskCheckpoint();
-      expectChanges(changes, [_removeKey('b', 2)]);
+      return new Future(() {
+        expectChanges(changes, [_removeKey('b', 2)]);
+      });
     });
 
-    observeTest('remove and add back', () {
+    test('remove and add back', () {
       map.remove('b');
       map['b'] = 2;
       expect(map, {'a': 1, 'b': 2, 'c': 3});
-      performMicrotaskCheckpoint();
-      expectChanges(changes,
-          [_removeKey('b', 2), _insertKey('b', 2)]);
+      return new Future(() {
+        expectChanges(changes,
+            [_removeKey('b', 2), _insertKey('b', 2)]);
+      });
     });
   });
 
-  observeTest('toString', () {
+  test('toString', () {
     var map = toObservable({'a': 1, 'b': 2});
     expect(map.toString(), '{a: 1, b: 2}');
   });
@@ -183,7 +200,7 @@
 
     tearDown(sharedTearDown);
 
-    observeTest('read operations', () {
+    test('read operations', () {
       expect(map.length, 2);
       expect(map.isEmpty, false);
       expect(map['a'], 1);
@@ -195,65 +212,69 @@
       var copy = {};
       map.forEach((k, v) { copy[k] = v; });
       expect(copy, {'a': 1, 'b': 2});
-      performMicrotaskCheckpoint();
+      return new Future(() {
+        // no change from read-only operators
+        expect(records, null);
 
-      // no change from read-only operators
-      expect(records, null);
-
-      // Make a change so the subscription gets unregistered.
-      map.clear();
+        // Make a change so the subscription gets unregistered.
+        map.clear();
+      });
     });
 
-    observeTest('putIfAbsent', () {
+    test('putIfAbsent', () {
       map.putIfAbsent('a', () => 42);
       expect(map, {'a': 1, 'b': 2});
 
       map.putIfAbsent('c', () => 3);
       expect(map, {'a': 1, 'b': 2, 'c': 3});
 
-      performMicrotaskCheckpoint();
-      expectChanges(records, [
-        _lengthChange(map, 2, 3),
-        _insertKey('c', 3),
-      ]);
+      return new Future(() {
+        expectChanges(records, [
+          _lengthChange(map, 2, 3),
+          _insertKey('c', 3),
+        ]);
+      });
     });
 
-    observeTest('[]=', () {
+    test('[]=', () {
       map['a'] = 42;
       expect(map, {'a': 42, 'b': 2});
 
       map['c'] = 3;
       expect(map, {'a': 42, 'b': 2, 'c': 3});
 
-      performMicrotaskCheckpoint();
-      expectChanges(records, [
-        _changeKey('a', 1, 42),
-        _lengthChange(map, 2, 3),
-        _insertKey('c', 3)
-      ]);
+      return new Future(() {
+        expectChanges(records, [
+          _changeKey('a', 1, 42),
+          _lengthChange(map, 2, 3),
+          _insertKey('c', 3)
+        ]);
+      });
     });
 
-    observeTest('remove', () {
+    test('remove', () {
       map.remove('b');
       expect(map, {'a': 1});
 
-      performMicrotaskCheckpoint();
-      expectChanges(records, [
-        _removeKey('b', 2),
-        _lengthChange(map, 2, 1),
-      ]);
+      return new Future(() {
+        expectChanges(records, [
+          _removeKey('b', 2),
+          _lengthChange(map, 2, 1),
+        ]);
+      });
     });
 
-    observeTest('clear', () {
+    test('clear', () {
       map.clear();
       expect(map, {});
 
-      performMicrotaskCheckpoint();
-      expectChanges(records, [
-        _removeKey('a', 1),
-        _removeKey('b', 2),
-        _lengthChange(map, 2, 0),
-      ]);
+      return new Future(() {
+        expectChanges(records, [
+          _removeKey('a', 1),
+          _removeKey('b', 2),
+          _lengthChange(map, 2, 0),
+        ]);
+      });
     });
   });
 }
diff --git a/pkg/observe/test/observe_test.dart b/pkg/observe/test/observe_test.dart
index 9376ed3..f973db9 100644
--- a/pkg/observe/test/observe_test.dart
+++ b/pkg/observe/test/observe_test.dart
@@ -9,11 +9,13 @@
 import 'package:unittest/unittest.dart';
 import 'observe_test_utils.dart';
 
-void main() {
+main() => dirtyCheckZone().run(_tests);
+
+void _tests() {
   // Note: to test the basic Observable system, we use ObservableBox due to its
   // simplicity. We also test a variant that is based on dirty-checking.
 
-  observeTest('no observers at the start', () {
+  test('no observers at the start', () {
     expect(dirty_check.allObservablesCount, 0);
   });
 
@@ -73,18 +75,18 @@
 
   tearDown(() {
     for (var sub in subs) sub.cancel();
-    performMicrotaskCheckpoint();
-
-    expect(dirty_check.allObservablesCount, initialObservers,
-        reason: 'Observable object leaked');
+    return new Future(() {
+      expect(dirty_check.allObservablesCount, initialObservers,
+          reason: 'Observable object leaked');
+    });
   });
 
-  observeTest('handle future result', () {
+  test('handle future result', () {
     var callback = expectAsync0((){});
     return new Future(callback);
   });
 
-  observeTest('no observers', () {
+  test('no observers', () {
     var t = createModel(123);
     expect(t.value, 123);
     t.value = 42;
@@ -92,7 +94,7 @@
     expect(t.hasObservers, false);
   });
 
-  observeTest('listen adds an observer', () {
+  test('listen adds an observer', () {
     var t = createModel(123);
     expect(t.hasObservers, false);
 
@@ -100,7 +102,7 @@
     expect(t.hasObservers, true);
   });
 
-  observeTest('changes delived async', () {
+  test('changes delived async', () {
     var t = createModel(123);
     int called = 0;
 
@@ -114,7 +116,7 @@
     expect(called, 0);
   });
 
-  observeTest('cause changes in handler', () {
+  test('cause changes in handler', () {
     var t = createModel(123);
     int called = 0;
 
@@ -130,7 +132,7 @@
     t.value = 42;
   });
 
-  observeTest('multiple observers', () {
+  test('multiple observers', () {
     var t = createModel(123);
 
     verifyRecords(records) {
@@ -144,7 +146,7 @@
     t.value = 42;
   });
 
-  observeTest('performMicrotaskCheckpoint', () {
+  test('async processing model', () {
     var t = createModel(123);
     var records = [];
     subs.add(t.changes.listen((r) { records.addAll(r); }));
@@ -152,22 +154,23 @@
     t.value = 42;
     expectChanges(records, [], reason: 'changes delived async');
 
-    performMicrotaskCheckpoint();
-    expectPropertyChanges(records, watch ? 1 : 2);
-    records.clear();
+    return new Future(() {
+      expectPropertyChanges(records, watch ? 1 : 2);
+      records.clear();
 
-    t.value = 777;
-    expectChanges(records, [], reason: 'changes delived async');
+      t.value = 777;
+      expectChanges(records, [], reason: 'changes delived async');
 
-    performMicrotaskCheckpoint();
-    expectPropertyChanges(records, 1);
+    }).then(newMicrotask).then((_) {
+      expectPropertyChanges(records, 1);
 
-    // Has no effect if there are no changes
-    performMicrotaskCheckpoint();
-    expectPropertyChanges(records, 1);
+      // Has no effect if there are no changes
+      Observable.dirtyCheck();
+      expectPropertyChanges(records, 1);
+    });
   });
 
-  observeTest('cancel listening', () {
+  test('cancel listening', () {
     var t = createModel(123);
     var sub;
     sub = t.changes.listen(expectAsync1((records) {
@@ -179,7 +182,7 @@
     t.value = 42;
   });
 
-  observeTest('cancel and reobserve', () {
+  test('cancel and reobserve', () {
     var t = createModel(123);
     var sub;
     sub = t.changes.listen(expectAsync1((records) {
@@ -197,47 +200,50 @@
     t.value = 42;
   });
 
-  observeTest('cannot modify changes list', () {
+  test('cannot modify changes list', () {
     var t = createModel(123);
     var records = null;
     subs.add(t.changes.listen((r) { records = r; }));
     t.value = 42;
 
-    performMicrotaskCheckpoint();
-    expectPropertyChanges(records, 1);
+    return new Future(() {
+      expectPropertyChanges(records, 1);
 
-    // Verify that mutation operations on the list fail:
+      // Verify that mutation operations on the list fail:
 
-    expect(() {
-      records[0] = new PropertyChangeRecord(t, #value, 0, 1);
-    }, throwsUnsupportedError);
+      expect(() {
+        records[0] = new PropertyChangeRecord(t, #value, 0, 1);
+      }, throwsUnsupportedError);
 
-    expect(() { records.clear(); }, throwsUnsupportedError);
+      expect(() { records.clear(); }, throwsUnsupportedError);
 
-    expect(() { records.length = 0; }, throwsUnsupportedError);
+      expect(() { records.length = 0; }, throwsUnsupportedError);
+    });
   });
 
-  observeTest('notifyChange', () {
+  test('notifyChange', () {
     var t = createModel(123);
     var records = [];
     subs.add(t.changes.listen((r) { records.addAll(r); }));
     t.notifyChange(new PropertyChangeRecord(t, #value, 123, 42));
 
-    performMicrotaskCheckpoint();
-    expectPropertyChanges(records, 1);
-    expect(t.value, 123, reason: 'value did not actually change.');
+    return new Future(() {
+      expectPropertyChanges(records, 1);
+      expect(t.value, 123, reason: 'value did not actually change.');
+    });
   });
 
-  observeTest('notifyPropertyChange', () {
+  test('notifyPropertyChange', () {
     var t = createModel(123);
     var records = null;
     subs.add(t.changes.listen((r) { records = r; }));
     expect(t.notifyPropertyChange(#value, t.value, 42), 42,
         reason: 'notifyPropertyChange returns newValue');
 
-    performMicrotaskCheckpoint();
-    expectPropertyChanges(records, 1);
-    expect(t.value, 123, reason: 'value did not actually change.');
+    return new Future(() {
+      expectPropertyChanges(records, 1);
+      expect(t.value, 123, reason: 'value did not actually change.');
+    });
   });
 }
 
diff --git a/pkg/observe/test/observe_test_utils.dart b/pkg/observe/test/observe_test_utils.dart
index af447dc..02a88e2 100644
--- a/pkg/observe/test/observe_test_utils.dart
+++ b/pkg/observe/test/observe_test_utils.dart
@@ -4,12 +4,16 @@
 
 library observe.test.observe_test_utils;
 
+import 'dart:async';
 import 'package:observe/observe.dart';
-
 import 'package:unittest/unittest.dart';
+export 'package:observe/src/dirty_check.dart' show dirtyCheckZone;
 
-import 'package:observe/src/microtask.dart';
-export 'package:observe/src/microtask.dart';
+/// A small method to help readability. Used to cause the next "then" in a chain
+/// to happen in the next microtask:
+///
+///     future.then(newMicrotask).then(...)
+newMicrotask(_) => new Future.value();
 
 // TODO(jmesserly): use matchers when we have a way to compare ChangeRecords.
 // For now just use the toString.
@@ -21,13 +25,3 @@
 
 List getPropertyChangeRecords(List changes, Symbol property) => changes
     .where((c) => c is PropertyChangeRecord && c.name == property).toList();
-
-/**
- * This is a special kind of unit [test], that supports
- * calling [performMicrotaskCheckpoint] during the test to pump events
- * that original from observable objects.
- */
-observeTest(name, testCase) => test(name, wrapMicrotask(testCase));
-
-/** The [solo_test] version of [observeTest]. */
-solo_observeTest(name, testCase) => solo_test(name, wrapMicrotask(testCase));
diff --git a/pkg/observe/test/path_observer_test.dart b/pkg/observe/test/path_observer_test.dart
index dcb8853..0993c69 100644
--- a/pkg/observe/test/path_observer_test.dart
+++ b/pkg/observe/test/path_observer_test.dart
@@ -2,6 +2,7 @@
 // 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.
 
+import 'dart:async';
 import 'package:observe/observe.dart';
 import 'package:unittest/unittest.dart';
 import 'observe_test_utils.dart';
@@ -9,240 +10,293 @@
 // This file contains code ported from:
 // https://github.com/rafaelw/ChangeSummary/blob/master/tests/test.js
 
-main() {
+main() => dirtyCheckZone().run(() {
   group('PathObserver', observePathTests);
-}
 
-observePath(obj, path) => new PathObserver(obj, path);
+  group('PropertyPath', () {
+    test('toString length', () {
+      expectPath(p, str, len) {
+        var path = new PropertyPath(p);
+        expect(path.toString(), str);
+        expect(path.length, len, reason: 'expected path length $len for $path');
+      }
+
+      expectPath('/foo', '<invalid path>', 0);
+      expectPath('abc', 'abc', 1);
+      expectPath('a.b.c', 'a.b.c', 3);
+      expectPath('a.b.c ', 'a.b.c', 3);
+      expectPath(' a.b.c', 'a.b.c', 3);
+      expectPath('  a.b.c   ', 'a.b.c', 3);
+      expectPath('1.abc', '1.abc', 2);
+      expectPath([#qux], 'qux', 1);
+      expectPath([1, #foo, #bar], '1.foo.bar', 3);
+    });
+
+    test('caching and ==', () {
+      var start = new PropertyPath('abc.0');
+      for (int i = 1; i <= 100; i++) {
+        expect(identical(new PropertyPath('abc.0'), start), true,
+          reason: 'should return identical path');
+
+        var p = new PropertyPath('abc.$i');
+        expect(identical(p, start), false,
+            reason: 'different paths should not be merged');
+      }
+      var end = new PropertyPath('abc.0');
+      expect(identical(end, start), false,
+          reason: 'first entry expired');
+      expect(end, start, reason: 'different instances are equal');
+    });
+
+    test('hashCode equal', () {
+      var a = new PropertyPath([#foo, 2, #bar]);
+      var b = new PropertyPath('foo.2.bar');
+      expect(identical(a, b), false, reason: 'only strings cached');
+      expect(a, b, reason: 'same paths are equal');
+      expect(a.hashCode, b.hashCode, reason: 'equal hashCodes');
+    });
+
+    test('hashCode not equal', () {
+      expect(2.hashCode, isNot(3.hashCode),
+          reason: 'test depends on 2 and 3 having different hashcodes');
+
+      var a = new PropertyPath([2]);
+      var b = new PropertyPath([3]);
+      expect(a, isNot(b), reason: 'different paths');
+      expect(a.hashCode, isNot(b.hashCode), reason: 'different hashCodes');
+    });
+  });
+});
+
 
 observePathTests() {
-  observeTest('Degenerate Values', () {
-    expect(observePath(null, '').value, null);
-    expect(observePath(123, '').value, 123);
-    expect(observePath(123, 'foo.bar.baz').value, null);
+  test('Degenerate Values', () {
+    expect(new PathObserver(null, '').value, null);
+    expect(new PathObserver(123, '').value, 123);
+    expect(new PathObserver(123, 'foo.bar.baz').value, null);
 
     // shouldn't throw:
-    observePath(123, '').changes.listen((_) {}).cancel();
-    observePath(null, '').value = null;
-    observePath(123, '').value = 42;
-    observePath(123, 'foo.bar.baz').value = 42;
+    new PathObserver(123, '')..open((_) {})..close();
+    new PropertyPath('').setValueFrom(null, null);
+    new PropertyPath('').setValueFrom(123, 42);
+    new PropertyPath('foo.bar.baz').setValueFrom(123, 42);
 
     var foo = {};
-    expect(observePath(foo, '').value, foo);
+    expect(new PathObserver(foo, '').value, foo);
 
     foo = new Object();
-    expect(observePath(foo, '').value, foo);
+    expect(new PathObserver(foo, '').value, foo);
 
-    expect(observePath(foo, 'a/3!').value, null);
+    expect(new PathObserver(foo, 'a/3!').value, null);
   });
 
-  observeTest('get value at path ObservableBox', () {
+  test('get value at path ObservableBox', () {
     var obj = new ObservableBox(new ObservableBox(new ObservableBox(1)));
 
-    expect(observePath(obj, '').value, obj);
-    expect(observePath(obj, 'value').value, obj.value);
-    expect(observePath(obj, 'value.value').value, obj.value.value);
-    expect(observePath(obj, 'value.value.value').value, 1);
+    expect(new PathObserver(obj, '').value, obj);
+    expect(new PathObserver(obj, 'value').value, obj.value);
+    expect(new PathObserver(obj, 'value.value').value, obj.value.value);
+    expect(new PathObserver(obj, 'value.value.value').value, 1);
 
     obj.value.value.value = 2;
-    expect(observePath(obj, 'value.value.value').value, 2);
+    expect(new PathObserver(obj, 'value.value.value').value, 2);
 
     obj.value.value = new ObservableBox(3);
-    expect(observePath(obj, 'value.value.value').value, 3);
+    expect(new PathObserver(obj, 'value.value.value').value, 3);
 
     obj.value = new ObservableBox(4);
-    expect(observePath(obj, 'value.value.value').value, null);
-    expect(observePath(obj, 'value.value').value, 4);
+    expect(new PathObserver(obj, 'value.value.value').value, null);
+    expect(new PathObserver(obj, 'value.value').value, 4);
   });
 
 
-  observeTest('get value at path ObservableMap', () {
+  test('get value at path ObservableMap', () {
     var obj = toObservable({'a': {'b': {'c': 1}}});
 
-    expect(observePath(obj, '').value, obj);
-    expect(observePath(obj, 'a').value, obj['a']);
-    expect(observePath(obj, 'a.b').value, obj['a']['b']);
-    expect(observePath(obj, 'a.b.c').value, 1);
+    expect(new PathObserver(obj, '').value, obj);
+    expect(new PathObserver(obj, 'a').value, obj['a']);
+    expect(new PathObserver(obj, 'a.b').value, obj['a']['b']);
+    expect(new PathObserver(obj, 'a.b.c').value, 1);
 
     obj['a']['b']['c'] = 2;
-    expect(observePath(obj, 'a.b.c').value, 2);
+    expect(new PathObserver(obj, 'a.b.c').value, 2);
 
     obj['a']['b'] = toObservable({'c': 3});
-    expect(observePath(obj, 'a.b.c').value, 3);
+    expect(new PathObserver(obj, 'a.b.c').value, 3);
 
     obj['a'] = toObservable({'b': 4});
-    expect(observePath(obj, 'a.b.c').value, null);
-    expect(observePath(obj, 'a.b').value, 4);
+    expect(new PathObserver(obj, 'a.b.c').value, null);
+    expect(new PathObserver(obj, 'a.b').value, 4);
   });
 
-  observeTest('set value at path', () {
+  test('set value at path', () {
     var obj = toObservable({});
-    observePath(obj, 'foo').value = 3;
+    new PropertyPath('foo').setValueFrom(obj, 3);
     expect(obj['foo'], 3);
 
     var bar = toObservable({ 'baz': 3 });
-    observePath(obj, 'bar').value = bar;
+    new PropertyPath('bar').setValueFrom(obj, bar);
     expect(obj['bar'], bar);
 
-    observePath(obj, 'bar.baz.bat').value = 'not here';
-    expect(observePath(obj, 'bar.baz.bat').value, null);
+    new PropertyPath('bar.baz.bat').setValueFrom(obj, 'not here');
+    expect(new PathObserver(obj, 'bar.baz.bat').value, null);
   });
 
-  observeTest('set value back to same', () {
+  test('set value back to same', () {
     var obj = toObservable({});
-    var path = observePath(obj, 'foo');
+    var path = new PathObserver(obj, 'foo');
     var values = [];
-    path.changes.listen((_) { values.add(path.value); });
+    path.open((x) {
+      expect(x, path.value, reason: 'callback should get current value');
+      values.add(x);
+    });
 
     path.value = 3;
     expect(obj['foo'], 3);
     expect(path.value, 3);
 
-    observePath(obj, 'foo').value = 2;
-    performMicrotaskCheckpoint();
-    expect(path.value, 2);
-    expect(observePath(obj, 'foo').value, 2);
+    new PropertyPath('foo').setValueFrom(obj, 2);
+    return new Future(() {
+      expect(path.value, 2);
+      expect(new PathObserver(obj, 'foo').value, 2);
 
-    observePath(obj, 'foo').value = 3;
-    performMicrotaskCheckpoint();
-    expect(path.value, 3);
+      new PropertyPath('foo').setValueFrom(obj, 3);
+    }).then(newMicrotask).then((_) {
+      expect(path.value, 3);
 
-    performMicrotaskCheckpoint();
-    expect(values, [2, 3]);
+    }).then(newMicrotask).then((_) {
+      expect(values, [2, 3]);
+    });
   });
 
-  observeTest('Observe and Unobserve - Paths', () {
+  test('Observe and Unobserve - Paths', () {
     var arr = toObservable({});
 
     arr['foo'] = 'bar';
     var fooValues = [];
-    var fooPath = observePath(arr, 'foo');
-    var fooSub = fooPath.changes.listen((_) {
-      fooValues.add(fooPath.value);
-    });
+    var fooPath = new PathObserver(arr, 'foo');
+    fooPath.open(fooValues.add);
     arr['foo'] = 'baz';
     arr['bat'] = 'bag';
     var batValues = [];
-    var batPath = observePath(arr, 'bat');
-    var batSub = batPath.changes.listen((_) {
-      batValues.add(batPath.value);
+    var batPath = new PathObserver(arr, 'bat');
+    batPath.open(batValues.add);
+
+    return new Future(() {
+      expect(fooValues, ['baz']);
+      expect(batValues, []);
+
+      arr['foo'] = 'bar';
+      fooPath.close();
+      arr['bat'] = 'boo';
+      batPath.close();
+      arr['bat'] = 'boot';
+
+    }).then(newMicrotask).then((_) {
+      expect(fooValues, ['baz']);
+      expect(batValues, []);
     });
-
-    performMicrotaskCheckpoint();
-    expect(fooValues, ['baz']);
-    expect(batValues, []);
-
-    arr['foo'] = 'bar';
-    fooSub.cancel();
-    arr['bat'] = 'boo';
-    batSub.cancel();
-    arr['bat'] = 'boot';
-
-    performMicrotaskCheckpoint();
-    expect(fooValues, ['baz']);
-    expect(batValues, []);
   });
 
-  observeTest('Path Value With Indices', () {
+  test('Path Value With Indices', () {
     var model = toObservable([]);
-    var path = observePath(model, '0');
-    path.changes.listen(expectAsync1((_) {
+    var path = new PathObserver(model, '0');
+    path.open(expectAsync1((x) {
       expect(path.value, 123);
+      expect(x, 123);
     }));
     model.add(123);
   });
 
   group('ObservableList', () {
-    observeTest('isNotEmpty', () {
+    test('isNotEmpty', () {
       var model = new ObservableList();
-      var path = observePath(model, 'isNotEmpty');
+      var path = new PathObserver(model, 'isNotEmpty');
       expect(path.value, false);
 
-      var future = path.changes.first.then((_) {
+      path.open(expectAsync1((_) {
         expect(path.value, true);
-      });
+      }));
       model.add(123);
-
-      return future;
     });
 
-    observeTest('isEmpty', () {
+    test('isEmpty', () {
       var model = new ObservableList();
-      var path = observePath(model, 'isEmpty');
+      var path = new PathObserver(model, 'isEmpty');
       expect(path.value, true);
 
-      var future = path.changes.first.then((_) {
+      path.open(expectAsync1((_) {
         expect(path.value, false);
-      });
+      }));
       model.add(123);
-
-      return future;
     });
   });
 
   for (var createModel in [() => new TestModel(), () => new WatcherModel()]) {
-    observeTest('Path Observation - ${createModel().runtimeType}', () {
+    test('Path Observation - ${createModel().runtimeType}', () {
       var model = createModel()..a =
           (createModel()..b = (createModel()..c = 'hello, world'));
 
-      var path = observePath(model, 'a.b.c');
+      var path = new PathObserver(model, 'a.b.c');
       var lastValue = null;
-      var sub = path.changes.listen((_) { lastValue = path.value; });
+      path.open((x) { lastValue = x; });
 
       model.a.b.c = 'hello, mom';
 
       expect(lastValue, null);
-      performMicrotaskCheckpoint();
-      expect(lastValue, 'hello, mom');
+      return new Future(() {
+        expect(lastValue, 'hello, mom');
 
-      model.a.b = createModel()..c = 'hello, dad';
-      performMicrotaskCheckpoint();
-      expect(lastValue, 'hello, dad');
+        model.a.b = createModel()..c = 'hello, dad';
+      }).then(newMicrotask).then((_) {
+        expect(lastValue, 'hello, dad');
 
-      model.a = createModel()..b =
-          (createModel()..c = 'hello, you');
-      performMicrotaskCheckpoint();
-      expect(lastValue, 'hello, you');
+        model.a = createModel()..b =
+            (createModel()..c = 'hello, you');
+      }).then(newMicrotask).then((_) {
+        expect(lastValue, 'hello, you');
 
-      model.a.b = 1;
-      performMicrotaskCheckpoint();
-      expect(lastValue, null);
+        model.a.b = 1;
+      }).then(newMicrotask).then((_) {
+        expect(lastValue, null);
 
-      // Stop observing
-      sub.cancel();
+        // Stop observing
+        path.close();
 
-      model.a.b = createModel()..c = 'hello, back again -- but not observing';
-      performMicrotaskCheckpoint();
-      expect(lastValue, null);
+        model.a.b = createModel()..c = 'hello, back again -- but not observing';
+      }).then(newMicrotask).then((_) {
+        expect(lastValue, null);
 
-      // Resume observing
-      sub = path.changes.listen((_) { lastValue = path.value; });
+        // Resume observing
+        new PathObserver(model, 'a.b.c').open((x) { lastValue = x; });
 
-      model.a.b.c = 'hello. Back for reals';
-      performMicrotaskCheckpoint();
-      expect(lastValue, 'hello. Back for reals');
+        model.a.b.c = 'hello. Back for reals';
+      }).then(newMicrotask).then((_) {
+        expect(lastValue, 'hello. Back for reals');
+      });
     });
   }
 
-  observeTest('observe map', () {
+  test('observe map', () {
     var model = toObservable({'a': 1});
-    var path = observePath(model, 'a');
+    var path = new PathObserver(model, 'a');
 
     var values = [path.value];
-    var sub = path.changes.listen((_) { values.add(path.value); });
+    path.open(values.add);
     expect(values, [1]);
 
     model['a'] = 2;
-    performMicrotaskCheckpoint();
-    expect(values, [1, 2]);
+    return new Future(() {
+      expect(values, [1, 2]);
 
-    sub.cancel();
-    model['a'] = 3;
-    performMicrotaskCheckpoint();
-    expect(values, [1, 2]);
+      path.close();
+      model['a'] = 3;
+    }).then(newMicrotask).then((_) {
+      expect(values, [1, 2]);
+    });
   });
 
-  observeTest('errors thrown from getter/setter', () {
+  test('errors thrown from getter/setter', () {
     var model = new ObjectWithErrors();
     var observer = new PathObserver(model, 'foo');
 
@@ -253,7 +307,7 @@
     expect(model.setFooCalled, [123]);
   });
 
-  observeTest('object with noSuchMethod', () {
+  test('object with noSuchMethod', () {
     var model = new NoSuchMethodModel();
     var observer = new PathObserver(model, 'foo');
 
@@ -271,7 +325,7 @@
     expect(observer.value, null, reason: 'path not found');
   });
 
-  observeTest('object with indexer', () {
+  test('object with indexer', () {
     var model = new IndexerModel();
     var observer = new PathObserver(model, 'foo');
 
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 90c23d2..83dce91 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -41,6 +41,9 @@
 collection/test/priority_queue_test: Pass, Slow # Issue 16426
 serialization/test/serialization_test: Skip
 
+[ $runtime == jsshell ]
+analyzer/test/generated/element_test: Pass, Slow # Issue 16473
+
 [ $runtime == d8 || $runtime == jsshell ]
 unittest/test/unittest_nested_groups_setup_teardown_test: RuntimeError # http://dartbug.com/10109
 stack_trace/test/vm_test: RuntimeError, OK # VM-specific traces
@@ -66,6 +69,7 @@
 polymer/test/prop_attr_bind_reflection_test: Skip #uses dart:html
 polymer/test/prop_attr_reflection_test: Skip #uses dart:html
 polymer/test/property_change_test: Skip # uses dart:html
+polymer/test/property_observe_test: Skip #uses dart:html
 polymer/test/publish_attributes_test: Skip #uses dart:html
 polymer/test/publish_inherited_properties_test: Skip #uses dart:html
 polymer/test/register_test: Skip #uses dart:html
@@ -96,7 +100,7 @@
 mime/test/mime_multipart_transformer_test: Skip # No typed_data on IE9.
 typed_data/test/typed_buffers_test: Fail, Crash # No typed_data on IE9.
 polymer/test/instance_attrs_test: Pass, Fail # Issue 14167
-polymer/test/bind_mdv_test: Pass, Fail # Issue 16441
+polymer/test/bind_mdv_test: Slow, Pass
 
 [ $runtime == safari ]
 fixnum/test/int_64_test: Pass, Fail # Bug in JSC.
@@ -106,7 +110,7 @@
 
 [ $runtime == ie9 || $runtime == ie10 ]
 polymer/test/bind_mdv_test: RuntimeError # Issue 14412, 13260
-polymer/test/noscript_test: RuntimeError # Issue 13260
+polymer/test/noscript_test: RuntimeError, Pass # Issue 13260
 
 # Skip browser-specific tests on VM
 [ $runtime == vm ]
@@ -115,7 +119,6 @@
 intl/test/date_time_format_http_request_test: Skip
 
 [ $runtime == vm && $system == windows ]
-docgen/test/single_library_test: Fail # Issue 11985
 intl/test/find_default_locale_standalone_test: Fail # Issue 8110
 
 [ $compiler == dartanalyzer ]
@@ -256,9 +259,12 @@
 unittest/test/unittest_correct_callback_test: Fail # 13921
 unittest/test/unittest_exception_test: Fail # 13921
 unittest/test/unittest_excess_callback_test: Fail # 13921
+unittest/test/unittest_group_name_test: Fail # 13921
+unittest/test/unittest_invalid_ops_test: Fail # 13921
 unittest/test/unittest_late_exception_test: Fail # 13921
 unittest/test/unittest_middle_exception_test: Fail # 13921
 unittest/test/unittest_nested_groups_setup_teardown_test: Fail # 13921
+unittest/test/unittest_protect_async_test: Fail # 13921
 unittest/test/unittest_runtests_without_tests_test: Fail # 13921
 unittest/test/unittest_setup_and_teardown_test: Fail # 13921
 unittest/test/unittest_setup_test: Fail # 13921
@@ -269,7 +275,6 @@
 unittest/test/unittest_test_returning_future_test: Fail # 13921
 unittest/test/unittest_test_returning_future_using_runasync_test: Fail # 13921
 unittest/test/unittest_testcases_immutable_test: Fail # 13921
-unittest/test/unitttest_group_name_test: Fail # 13921
 polymer/test/custom_event_test: Pass, Crash # 14360
 polymer/example/canonicalization/test/deploy_test: Fail, OK # tests deploy only behavior
 polymer/example/canonicalization/test/deploy2_test: Fail, OK # tests deploy only behavior
@@ -290,6 +295,9 @@
 polymer_expressions/test/bindings_test: Skip
 third_party/html5lib/test/browser/browser_test: Skip
 
+[ $runtime == safari || $runtime == ie9 || $runtime == ie10 ]
+polymer_expressions/test/globals_test: Fail # Issue 16568
+
 [ $runtime == safari || $runtime == chrome || $runtime == ie9 || $runtime == ff || $runtime == dartium || $runtime == drt ]
 docgen/test/single_library_test: Skip # Uses dart:io
 docgen/test/multi_library_test: Skip # Uses dart:io
@@ -301,7 +309,6 @@
 
 [ $compiler == none && ($runtime == dartium || $runtime == drt) ]
 source_maps/test/parser_test: Pass, Timeout # Issue 13719: Please triage this failure.
-polymer_expressions/test/bindings_test: Fail, Pass # Issue 14445.
 
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
 docgen/test/single_library_test: StaticWarning
diff --git a/pkg/pkgbuild.status b/pkg/pkgbuild.status
index cfcca4d..8ee3ed75 100644
--- a/pkg/pkgbuild.status
+++ b/pkg/pkgbuild.status
@@ -4,6 +4,7 @@
 
 third_party/pkg/route_hierarchical: Fail
 
+samples/third_party/angular_todo: Pass, Slow
 samples/third_party/pop-pop-win: Pass, Slow
 samples/searchable_list: Pass, Slow
 pkg/docgen: Pass, Slow
@@ -17,6 +18,7 @@
 
 [ $use_public_packages ]
 pkg/watcher: PubGetError # Issue 16026
+pkg/template_binding: Pass, PubGetError # Issue 16026
 
 [ $builder_tag == russian ]
 samples/third_party/pop-pop-win: Fail # Issue 16356
diff --git a/pkg/polymer/CHANGELOG.md b/pkg/polymer/CHANGELOG.md
index 01e65d6..d732a88 100644
--- a/pkg/polymer/CHANGELOG.md
+++ b/pkg/polymer/CHANGELOG.md
@@ -5,6 +5,15 @@
 impact polymer: custom_element, html_import, observe, shadow_dom,
 and template_binding.
 
+#### Pub version 0.10.0-dev
+  * Deploy step removes use of mirrors to initialize polymer elements. Mirrors
+    are still used for @published and for polymer-expressions.
+    **breaking change**: @initMethod and @CustomTag are only supported on
+    public classes/methods.
+
+#### Pub version 0.9.5
+  * Improvements on how to handle cross-package HTML imports.
+
 #### Pub version 0.9.4
   * Removes unused dependency on csslib.
 
diff --git a/pkg/polymer/example/canonicalization/lib/a.dart b/pkg/polymer/example/canonicalization/lib/a.dart
index 78426db..dfbe3ca 100644
--- a/pkg/polymer/example/canonicalization/lib/a.dart
+++ b/pkg/polymer/example/canonicalization/lib/a.dart
@@ -9,7 +9,7 @@
 import 'd.dart';
 
 int a = 0;
-@initMethod _init() {
+@initMethod initA() {
   a++;
   c++;
   d++;
diff --git a/pkg/polymer/example/canonicalization/lib/b.dart b/pkg/polymer/example/canonicalization/lib/b.dart
index 0a3a29d..fbdccf6 100644
--- a/pkg/polymer/example/canonicalization/lib/b.dart
+++ b/pkg/polymer/example/canonicalization/lib/b.dart
@@ -9,7 +9,7 @@
 import 'd.dart';
 
 int b = 0;
-@initMethod _init() {
+@initMethod initB() {
   b++;
   c++;
   d++;
diff --git a/pkg/polymer/example/canonicalization2/lib/a.dart b/pkg/polymer/example/canonicalization2/lib/a.dart
index 78426db..dfbe3ca 100644
--- a/pkg/polymer/example/canonicalization2/lib/a.dart
+++ b/pkg/polymer/example/canonicalization2/lib/a.dart
@@ -9,7 +9,7 @@
 import 'd.dart';
 
 int a = 0;
-@initMethod _init() {
+@initMethod initA() {
   a++;
   c++;
   d++;
diff --git a/pkg/polymer/example/canonicalization2/lib/b.dart b/pkg/polymer/example/canonicalization2/lib/b.dart
index 0a3a29d..fbdccf6 100644
--- a/pkg/polymer/example/canonicalization2/lib/b.dart
+++ b/pkg/polymer/example/canonicalization2/lib/b.dart
@@ -9,7 +9,7 @@
 import 'd.dart';
 
 int b = 0;
-@initMethod _init() {
+@initMethod initB() {
   b++;
   c++;
   d++;
diff --git a/pkg/polymer/example/canonicalization3/lib/a.dart b/pkg/polymer/example/canonicalization3/lib/a.dart
index 78426db..dfbe3ca 100644
--- a/pkg/polymer/example/canonicalization3/lib/a.dart
+++ b/pkg/polymer/example/canonicalization3/lib/a.dart
@@ -9,7 +9,7 @@
 import 'd.dart';
 
 int a = 0;
-@initMethod _init() {
+@initMethod initA() {
   a++;
   c++;
   d++;
diff --git a/pkg/polymer/example/canonicalization3/lib/b.dart b/pkg/polymer/example/canonicalization3/lib/b.dart
index 0a3a29d..fbdccf6 100644
--- a/pkg/polymer/example/canonicalization3/lib/b.dart
+++ b/pkg/polymer/example/canonicalization3/lib/b.dart
@@ -9,7 +9,7 @@
 import 'd.dart';
 
 int b = 0;
-@initMethod _init() {
+@initMethod initB() {
   b++;
   c++;
   d++;
diff --git a/pkg/polymer/lib/polymer.dart b/pkg/polymer/lib/polymer.dart
index ff80921..8ccfaff 100644
--- a/pkg/polymer/lib/polymer.dart
+++ b/pkg/polymer/lib/polymer.dart
@@ -40,7 +40,7 @@
 library polymer;
 
 import 'dart:async';
-import 'dart:collection' show HashMap;
+import 'dart:collection' show HashMap, HashSet;
 import 'dart:html';
 import 'dart:js' as js;
 
diff --git a/pkg/polymer/lib/src/build/code_extractor.dart b/pkg/polymer/lib/src/build/code_extractor.dart
index e6c6445..a349f08 100644
--- a/pkg/polymer/lib/src/build/code_extractor.dart
+++ b/pkg/polymer/lib/src/build/code_extractor.dart
@@ -7,7 +7,6 @@
 
 import 'dart:async';
 
-import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/parser.dart';
@@ -73,7 +72,7 @@
 /** Parse [code] and determine whether it has a library directive. */
 bool _hasLibraryDirective(String code) {
   var errorListener = new _ErrorCollector();
-  var reader = new CharSequenceReader(new CharSequence(code));
+  var reader = new CharSequenceReader(code);
   var scanner = new Scanner(null, reader, errorListener);
   var token = scanner.tokenize();
   var unit = new Parser(null, errorListener).parseCompilationUnit(token);
diff --git a/pkg/polymer/lib/src/build/common.dart b/pkg/polymer/lib/src/build/common.dart
index 1b27f55..516c02c 100644
--- a/pkg/polymer/lib/src/build/common.dart
+++ b/pkg/polymer/lib/src/build/common.dart
@@ -117,13 +117,26 @@
   String toString() => 'polymer ($runtimeType)';
 }
 
-/** Create an [AssetId] for a [url] seen in the [source] asset. */
+/**
+ * Create an [AssetId] for a [url] seen in the [source] asset. By default this
+ * is used to resolve relative urls that occur in HTML assets, including
+ * cross-package urls of the form "packages/foo/bar.html". Dart-style "package:"
+ * urls are not resolved unless [source] is Dart file (has a .dart extension).
+ */
 // TODO(sigmund): delete once this is part of barback (dartbug.com/12610)
 AssetId resolve(AssetId source, String url, TransformLogger logger, Span span) {
   if (url == null || url == '') return null;
   var uri = Uri.parse(url);
   var urlBuilder = path.url;
   if (uri.host != '' || uri.scheme != '' || urlBuilder.isAbsolute(url)) {
+    if (source.extension == '.dart' && uri.scheme == 'package') {
+      var index = uri.path.indexOf('/');
+      if (index != -1) {
+        return new AssetId(uri.path.substring(0, index),
+            'lib${uri.path.substring(index)}');
+      }
+    } 
+
     logger.error('absolute paths not allowed: "$url"', span: span);
     return null;
   }
diff --git a/pkg/polymer/lib/src/build/script_compactor.dart b/pkg/polymer/lib/src/build/script_compactor.dart
index e869a2c..335fcb0 100644
--- a/pkg/polymer/lib/src/build/script_compactor.dart
+++ b/pkg/polymer/lib/src/build/script_compactor.dart
@@ -8,9 +8,14 @@
 import 'dart:async';
 import 'dart:convert';
 
+import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/scanner.dart';
 import 'package:barback/barback.dart';
 import 'package:html5lib/parser.dart' show parseFragment;
 import 'package:path/path.dart' as path;
+import 'package:source_maps/span.dart' show SourceFile;
 
 import 'code_extractor.dart'; // import just for documentation.
 import 'common.dart';
@@ -77,6 +82,7 @@
           return null;
         }
 
+        // Emit the bootstrap .dart file
         var bootstrapId = id.addExtension('_bootstrap.dart');
         mainScriptTag.attributes['src'] =
             path.url.basename(bootstrapId.path);
@@ -92,20 +98,187 @@
 
         buffer..write('\n')
             ..writeln('void main() {')
-            ..writeln('  configureForDeployment([')
-            ..writeAll(urls.map((url) => "      '$url',\n"))
-            ..writeln('    ]);')
-            ..writeln('  i${i - 1}.main();')
-            ..writeln('}');
+            ..writeln('  configureForDeployment([');
 
-        transform.addOutput(new Asset.fromString(
-              bootstrapId, buffer.toString()));
-        transform.addOutput(new Asset.fromString(id, document.outerHtml));
+        // Inject @CustomTag and @initMethod initializations for each library
+        // that is sourced in a script tag.
+        i = 0;
+        return Future.forEach(libraries, (lib) {
+          return _initializersOf(lib, transform, logger).then((initializers) {
+            for (var init in initializers) {
+              var code = init.asCode('i$i');
+              buffer.write("      $code,\n");
+            }
+            i++;
+          });
+        }).then((_) {
+          buffer..writeln('    ]);')
+              ..writeln('  i${urls.length - 1}.main();')
+              ..writeln('}');
+
+          transform.addOutput(new Asset.fromString(
+                bootstrapId, buffer.toString()));
+          transform.addOutput(new Asset.fromString(id, document.outerHtml));
+        });
       });
     });
   }
+
+  /**
+   * Computes the initializers of [dartLibrary]. That is, a closure that calls
+   * Polymer.register for each @CustomTag, and any public top-level methods
+   * labeled with @initMethod.
+   */
+  Future<List<_Initializer>> _initializersOf(
+      AssetId dartLibrary, Transform transform, TransformLogger logger) {
+    var initializers = [];
+    return transform.readInputAsString(dartLibrary).then((code) {
+      var file = new SourceFile.text(_simpleUriForSource(dartLibrary), code);
+      var unit = _parseCompilationUnit(code);
+
+      return Future.forEach(unit.directives, (directive) {
+        // Include anything from parts.
+        if (directive is PartDirective) {
+          var targetId = resolve(dartLibrary, directive.uri.stringValue,
+              logger, _getSpan(file, directive));
+          return _initializersOf(targetId, transform, logger)
+              .then(initializers.addAll);
+        }
+
+        // Similarly, include anything from exports except what's filtered by
+        // the show/hide combinators.
+        if (directive is ExportDirective) {
+          var targetId = resolve(dartLibrary, directive.uri.stringValue,
+              logger, _getSpan(file, directive));
+          return _initializersOf(targetId, transform, logger)
+              .then((r) => _processExportDirective(directive, r, initializers));
+        }
+      }).then((_) {
+        // Scan the code for classes and top-level functions.
+        for (var node in unit.declarations) {
+          if (node is ClassDeclaration) {
+            _processClassDeclaration(node, initializers, file, logger);
+          } else if (node is FunctionDeclaration &&
+              node.metadata.any(_isInitMethodAnnotation)) {
+            _processFunctionDeclaration(node, initializers, file, logger);
+          }
+        }
+        return initializers;
+      });
+    });
+  }
+
+  static String _simpleUriForSource(AssetId source) =>
+      source.path.startsWith('lib/')
+      ? 'package:${source.package}/${source.path.substring(4)}' : source.path;
+
+  /**
+   * Filter [exportedInitializers] according to [directive]'s show/hide
+   * combinators and add the result to [initializers].
+   */
+  // TODO(sigmund): call the analyzer's resolver instead?
+  static _processExportDirective(ExportDirective directive,
+      List<_Initializer> exportedInitializers,
+      List<_Initializer> initializers) {
+    for (var combinator in directive.combinators) {
+      if (combinator is ShowCombinator) {
+        var show = combinator.shownNames.map((n) => n.name).toSet();
+        exportedInitializers.retainWhere((e) => show.contains(e.symbolName));
+      } else if (combinator is HideCombinator) {
+        var hide = combinator.hiddenNames.map((n) => n.name).toSet();
+        exportedInitializers.removeWhere((e) => hide.contains(e.symbolName));
+      }
+    }
+    initializers.addAll(exportedInitializers);
+  }
+
+  /**
+   * Add an initializer to register [node] as a polymer element if it contains
+   * an appropriate [CustomTag] annotation.
+   */
+  static _processClassDeclaration(ClassDeclaration node,
+      List<_Initializer> initializers, SourceFile file,
+      TransformLogger logger) {
+    for (var meta in node.metadata) {
+      if (!_isCustomTagAnnotation(meta)) continue;
+      var args = meta.arguments.arguments;
+      if (args == null || args.length == 0) {
+        logger.error('Missing argument in @CustomTag annotation',
+            span: _getSpan(file, meta));
+        continue;
+      }
+
+      var tagName = args[0].stringValue;
+      var typeName = node.name.name;
+      if (typeName.startsWith('_')) {
+        logger.error('@CustomTag is no longer supported on private '
+          'classes: $tagName', span: _getSpan(file, node.name));
+        continue;
+      }
+      initializers.add(new _CustomTagInitializer(tagName, typeName));
+    }
+  }
+
+  /**  a method initializer for [function]. */
+  static _processFunctionDeclaration(FunctionDeclaration function,
+      List<_Initializer> initializers, SourceFile file,
+      TransformLogger logger) {
+    var name = function.name.name;
+    if (name.startsWith('_')) {
+      logger.error('@initMethod is no longer supported on private '
+        'functions: $name', span: _getSpan(file, function.name));
+      return;
+    }
+    initializers.add(new _InitMethodInitializer(name));
+  }
 }
 
+/** Parse [code] using analyzer. */
+CompilationUnit _parseCompilationUnit(String code) {
+  var errorListener = new _ErrorCollector();
+  var reader = new CharSequenceReader(code);
+  var scanner = new Scanner(null, reader, errorListener);
+  var token = scanner.tokenize();
+  var parser = new Parser(null, errorListener);
+  return parser.parseCompilationUnit(token);
+}
+
+class _ErrorCollector extends AnalysisErrorListener {
+  final errors = <AnalysisError>[];
+  onError(error) => errors.add(error);
+}
+
+// TODO(sigmund): consider support for importing annotations with prefixes.
+bool _isInitMethodAnnotation(Annotation node) =>
+    node.name.name == 'initMethod' && node.constructorName == null &&
+    node.arguments == null;
+bool _isCustomTagAnnotation(Annotation node) => node.name.name == 'CustomTag';
+
+abstract class _Initializer {
+  String get symbolName;
+  String asCode(String prefix);
+}
+
+class _InitMethodInitializer implements _Initializer {
+  String methodName;
+  String get symbolName => methodName;
+  _InitMethodInitializer(this.methodName);
+
+  String asCode(String prefix) => "$prefix.$methodName";
+}
+
+class _CustomTagInitializer implements _Initializer {
+  String tagName;
+  String typeName;
+  String get symbolName => typeName;
+  _CustomTagInitializer(this.tagName, this.typeName);
+
+  String asCode(String prefix) =>
+      "() => Polymer.register('$tagName', $prefix.$typeName)";
+}
+
+_getSpan(SourceFile file, ASTNode node) => file.span(node.offset, node.end);
+
 const MAIN_HEADER = """
 library app_bootstrap;
 
diff --git a/pkg/polymer/lib/src/declaration.dart b/pkg/polymer/lib/src/declaration.dart
index 7eaf11a..d120340 100644
--- a/pkg/polymer/lib/src/declaration.dart
+++ b/pkg/polymer/lib/src/declaration.dart
@@ -41,23 +41,29 @@
   PolymerDeclaration _super;
   PolymerDeclaration get superDeclaration => _super;
 
+  String _extendsName;
+
   String _name;
   String get name => _name;
 
   /**
    * Map of publish properties. Can be a [VariableMirror] or a [MethodMirror]
    * representing a getter. If it is a getter, there will also be a setter.
+   *
+   * Note: technically these are always single properties, so we could use
+   * a Symbol instead of a PropertyPath. However there are lookups between
+   * this map and [_observe] so it is easier to just track paths.
    */
-  Map<Symbol, DeclarationMirror> _publish;
+  Map<PropertyPath, DeclarationMirror> _publish;
 
   /** The names of published properties for this polymer-element. */
-  Iterable<Symbol> get publishedProperties =>
-      _publish != null ? _publish.keys : const [];
+  Iterable<String> get publishedProperties =>
+      _publish != null ? _publish.keys.map((p) => '$p') : const [];
 
   /** Same as [_publish] but with lower case names. */
   Map<String, DeclarationMirror> _publishLC;
 
-  Map<Symbol, Symbol> _observe;
+  Map<PropertyPath, List<Symbol>> _observe;
 
   Map<String, Object> _instanceAttributes;
 
@@ -83,6 +89,8 @@
   PolymerDeclaration.created() : super.created() {
     // fetch the element name
     _name = attributes['name'];
+    // fetch our extendee name
+    _extendsName = attributes['extends'];
     // install element definition, if ready
     registerWhenReady();
   }
@@ -92,9 +100,7 @@
     if (waitingForType(name)) {
       return;
     }
-    // fetch our extendee name
-    var extendee = attributes['extends'];
-    if (waitingForExtendee(extendee)) {
+    if (waitingForExtendee(_extendsName)) {
       //console.warn(name + ': waitingForExtendee:' + extendee);
       return;
     }
@@ -106,7 +112,7 @@
     // finalizing elements in the main document
     // TODO(jmesserly): Polymer.dart waits for HTMLImportsLoaded, so I've
     // removed "whenImportsLoaded" for now. Restore the workaround if needed.
-    _register(extendee);
+    _register(_extendsName);
   }
 
   void _register(extendee) {
@@ -188,10 +194,13 @@
     // transcribe `attributes` declarations onto own prototype's `publish`
     publishAttributes(cls, _super);
 
-    publishProperties(type);
+    publishProperties(_type);
 
     inferObservers(cls);
 
+    // desugar compound observer syntax, e.g. @ObserveProperty('a b c')
+    explodeObservers(cls);
+
     // Skip the rest in Dart:
     // chain various meta-data objects to inherited versions
     // chain custom api to inherited
@@ -209,6 +218,8 @@
     // install external stylesheets as if they are inline
     installSheets();
 
+    adjustShadowElement();
+
     // TODO(sorvell): install a helper method this.resolvePath to aid in
     // setting resource paths. e.g.
     // this.$.image.src = this.resolvePath('images/foo.png')
@@ -231,6 +242,22 @@
     }
   }
 
+  // TODO(sorvell): remove when spec addressed:
+  // https://www.w3.org/Bugs/Public/show_bug.cgi?id=22460
+  // make <shadow></shadow> be <shadow><content></content></shadow>
+  void adjustShadowElement() {
+    // TODO(sorvell): avoid under SD polyfill until this bug is addressed:
+    // https://github.com/Polymer/ShadowDOM/issues/297
+    if (!_hasShadowDomPolyfill) {
+      final content = templateContent;
+      if (content == null) return;
+
+      for (var s in content.querySelectorAll('shadow')) {
+        if (s.nodes.isEmpty) s.append(new ContentElement());
+      }
+    }
+  }
+
   void registerType(String name) {
     var baseTag;
     var decl = this;
@@ -257,16 +284,19 @@
     if (attrs != null) {
       // names='a b c' or names='a,b,c'
       // record each name for publishing
-      for (var attr in attrs.split(attrs.contains(',') ? ',' : ' ')) {
+      for (var attr in attrs.split(_ATTRIBUTES_REGEX)) {
         // remove excess ws
         attr = attr.trim();
 
         // do not override explicit entries
-        if (attr != '' && _publish != null && _publish.containsKey(attr)) {
+        if (attr == '') continue;
+
+        var property = new Symbol(attr);
+        var path = new PropertyPath([property]);
+        if (_publish != null && _publish.containsKey(path)) {
           continue;
         }
 
-        var property = new Symbol(attr);
         var mirror = _getProperty(cls, property);
         if (mirror == null) {
           window.console.warn('property for attribute $attr of polymer-element '
@@ -274,7 +304,7 @@
           continue;
         }
         if (_publish == null) _publish = {};
-        _publish[property] = mirror;
+        _publish[path] = mirror;
       }
     }
 
@@ -378,7 +408,7 @@
     var nodes = this.querySelectorAll(selector).toList();
     var content = templateContent;
     if (content != null) {
-      nodes = nodes..addAll(content.queryAll(selector));
+      nodes = nodes..addAll(content.querySelectorAll(selector));
     }
     if (matcher != null) return nodes.where(matcher).toList();
     return nodes;
@@ -408,7 +438,7 @@
     }
     // handle cached style elements
     for (var style in styles.where(matcher)) {
-      cssText..write(style.textContent)..write('\n\n');
+      cssText..write(style.text)..write('\n\n');
     }
     return cssText.toString();
   }
@@ -427,14 +457,11 @@
   }
 
   /**
-   * fetch a list of all observable properties names in our inheritance chain
-   * above Polymer.
+   * Fetch a list of all *Changed methods so we can observe the associated
+   * properties.
    */
-  // TODO(sjmiles): perf: reflection is slow, relatively speaking
-  // If an element may take 6us to create, getCustomPropertyNames might
-  // cost 1.6us more.
   void inferObservers(ClassMirror cls) {
-    if (cls == _objectType) return;
+    if (cls == _htmlElementType) return;
     inferObservers(cls.superclass);
     for (var method in cls.declarations.values) {
       if (method is! MethodMirror || method.isStatic
@@ -442,9 +469,36 @@
 
       String name = MirrorSystem.getName(method.simpleName);
       if (name.endsWith(_OBSERVE_SUFFIX) && name != 'attributeChanged') {
-        if (_observe == null) _observe = new Map();
+        // TODO(jmesserly): now that we have a better system, should we
+        // deprecate *Changed methods?
+        if (_observe == null) _observe = new HashMap();
         name = name.substring(0, name.length - 7);
-        _observe[new Symbol(name)] = method.simpleName;
+        _observe[new PropertyPath(name)] = [method.simpleName];
+      }
+    }
+  }
+
+  /**
+   * Fetch a list of all methods annotated with [ObserveProperty] so we can
+   * observe the associated properties.
+   */
+  void explodeObservers(ClassMirror cls) {
+    if (cls == _htmlElementType) return;
+
+    explodeObservers(cls.superclass);
+    for (var method in cls.declarations.values) {
+      if (method is! MethodMirror || method.isStatic
+          || !method.isRegularMethod) continue;
+
+      for (var meta in _safeGetMetadata(method)) {
+        if (meta.reflectee is! ObserveProperty) continue;
+
+        if (_observe == null) _observe = new HashMap();
+
+        for (String name in meta.reflectee.names) {
+          _observe.putIfAbsent(new PropertyPath(name), () => [])
+              .add(method.simpleName);
+        }
       }
     }
   }
@@ -454,10 +508,10 @@
     if (_publish != null) _publishLC = _lowerCaseMap(_publish);
   }
 
-  Map<String, dynamic> _lowerCaseMap(Map<Symbol, dynamic> properties) {
+  Map<String, dynamic> _lowerCaseMap(Map<PropertyPath, dynamic> properties) {
     final map = new Map<String, dynamic>();
-    properties.forEach((name, value) {
-      map[MirrorSystem.getName(name).toLowerCase()] = value;
+    properties.forEach((PropertyPath path, value) {
+      map['$path'.toLowerCase()] = value;
     });
     return map;
   }
@@ -495,10 +549,10 @@
 PolymerDeclaration _getDeclaration(String name) => _declarations[name];
 
 final _objectType = reflectClass(Object);
-
+final _htmlElementType = reflectClass(HtmlElement);
 
 Map _getPublishedProperties(ClassMirror cls, Map props) {
-  if (cls == _objectType) return props;
+  if (cls == _htmlElementType) return props;
   props = _getPublishedProperties(cls.superclass, props);
   for (var member in cls.declarations.values) {
     if (member.isStatic || member.isPrivate) continue;
@@ -512,7 +566,7 @@
           // it's a tad expensive.
           if (member is! MethodMirror || _hasSetter(cls, member)) {
             if (props == null) props = {};
-            props[member.simpleName] = member;
+            props[new PropertyPath([member.simpleName])] = member;
           }
           break;
         }
@@ -545,6 +599,19 @@
   return null;
 }
 
+List _safeGetMetadata(MethodMirror method) {
+  // TODO(jmesserly): dart2js blows up getting metadata from methods in some
+  // cases. Why does this happen? It seems like the culprit might be named
+  // arguments. Unfortunately even calling method.parameters also
+  // triggers the bug in computeFunctionRti. For now we guard against it
+  // with this check.
+  try {
+    return method.metadata;
+  } catch (e) {
+    return [];
+  }
+}
+
 bool _hasSetter(ClassMirror cls, MethodMirror getter) {
   var setterName = new Symbol('${MirrorSystem.getName(getter.simpleName)}=');
   var mirror = cls.declarations[setterName];
@@ -565,8 +632,7 @@
  */
 void _shimShadowDomStyling(DocumentFragment template, String name,
     String extendee) {
-  if (js.context == null || template == null) return;
-  if (!js.context.hasProperty('ShadowDOMPolyfill')) return;
+  if (template == null || !_hasShadowDomPolyfill) return;
 
   var platform = js.context['Platform'];
   if (platform == null) return;
@@ -575,6 +641,9 @@
   shadowCss.callMethod('shimStyling', [template, name, extendee]);
 }
 
+final bool _hasShadowDomPolyfill = js.context != null &&
+    js.context.hasProperty('ShadowDOMPolyfill');
+
 const _STYLE_SELECTOR = 'style';
 const _SHEET_SELECTOR = '[rel=stylesheet]';
 const _STYLE_GLOBAL_SCOPE = 'global';
@@ -627,6 +696,7 @@
 
   'domfocusout': 'DOMFocusOut',
   'domfocusin': 'DOMFocusIn',
+  'dommousescroll': 'DOMMouseScroll',
 
   // TODO(jmesserly): Dart specific renames. Reconcile with Polymer.js
   'animationend': 'webkitAnimationEnd',
@@ -657,3 +727,5 @@
   final result = _reverseEventTranslations[eventType];
   return result != null ? result : eventType;
 }
+
+final _ATTRIBUTES_REGEX = new RegExp(r'\s|,');
diff --git a/pkg/polymer/lib/src/instance.dart b/pkg/polymer/lib/src/instance.dart
index c0af66c..abc2a0c 100644
--- a/pkg/polymer/lib/src/instance.dart
+++ b/pkg/polymer/lib/src/instance.dart
@@ -13,7 +13,6 @@
  *       @published double volume;
  *     }
  */
-// TODO(jmesserly): does @published imply @observable or vice versa?
 const published = const PublishedProperty();
 
 /** An annotation used to publish a field as an attribute. See [published]. */
@@ -22,6 +21,37 @@
 }
 
 /**
+ * Use this type to observe a property and have the method be called when it
+ * changes. For example:
+ *
+ *     @ObserveProperty('foo.bar baz qux')
+ *     validate() {
+ *       // use this.foo.bar, this.baz, and this.qux in validation
+ *       ...
+ *     }
+ *
+ * Note that you can observe a property path, and more than a single property
+ * can be specified in a space-delimited list or as a constant List.
+ */
+class ObserveProperty {
+  final _names;
+
+  List<String> get names {
+    var n = _names;
+    // TODO(jmesserly): the bogus '$n' is to workaround a dart2js bug, otherwise
+    // it generates an incorrect call site.
+    if (n is String) return '$n'.split(' ');
+    if (n is! Iterable) {
+      throw new UnsupportedError('ObserveProperty takes either an Iterable of '
+          'names, or a space separated String, instead of `$n`.');
+    }
+    return n;
+  }
+
+  const ObserveProperty(this._names);
+}
+
+/**
  * The mixin class for Polymer elements. It provides convenience features on top
  * of the custom elements web standard.
  *
@@ -30,7 +60,7 @@
  */
 abstract class Polymer implements Element, Observable, NodeBindExtension {
   // Fully ported from revision:
-  // https://github.com/Polymer/polymer/blob/b7200854b2441a22ce89f6563963f36c50f5150d
+  // https://github.com/Polymer/polymer/blob/37eea00e13b9f86ab21c85a955585e8e4237e3d2
   //
   //   src/boot.js (static APIs on "Polymer" object)
   //   src/instance/attributes.js
@@ -88,7 +118,7 @@
   bool _unbound; // lazy-initialized
   _Job _unbindAllJob;
 
-  StreamSubscription _propertyObserver;
+  CompoundObserver _propertyObserver;
 
   bool get _elementPrepared => _declaration != null;
 
@@ -217,7 +247,7 @@
    * Return a shadow-root template (if desired), override for custom behavior.
    */
   Element fetchTemplate(Element elementElement) =>
-      elementElement.query('template');
+      elementElement.querySelector('template');
 
   /**
    * Utility function that stamps a `<template>` into light-dom.
@@ -379,29 +409,29 @@
 
     if (value is bool) {
       return _toBoolean(value) ? '' : null;
-    } else if (value is String || value is int || value is double) {
+    } else if (value is String || value is num) {
       return '$value';
     }
     return null;
   }
 
-  void reflectPropertyToAttribute(Symbol name) {
+  void reflectPropertyToAttribute(PropertyPath path) {
+    if (path.length != 1) throw new ArgumentError('path must be length 1');
+
     // TODO(sjmiles): consider memoizing this
-    final self = reflect(this);
     // try to intelligently serialize property value
-    // TODO(jmesserly): cache symbol?
-    final propValue = self.getField(name).reflectee;
+    final propValue = path.getValueFrom(this);
     final serializedValue = serializeValue(propValue);
     // boolean properties must reflect as boolean attributes
     if (serializedValue != null) {
-      attributes[MirrorSystem.getName(name)] = serializedValue;
+      attributes['$path'] = serializedValue;
       // TODO(sorvell): we should remove attr for all properties
       // that have undefined serialization; however, we will need to
       // refine the attr reflection system to achieve this; pica, for example,
       // relies on having inferredType object properties not removed as
       // attrs.
     } else if (propValue is bool) {
-      attributes.remove(MirrorSystem.getName(name));
+      attributes.remove('$path');
     }
   }
 
@@ -421,7 +451,9 @@
   DocumentFragment instanceTemplate(Element template) =>
       templateBind(template).createInstance(this, syntax);
 
-  NodeBinding bind(String name, model, [String path]) {
+  // TODO(jmesserly): Polymer does not seem to implement the oneTime flag
+  // correctly. File bug.
+  Bindable bind(String name, Bindable bindable, {bool oneTime: false}) {
     // note: binding is a prepare signal. This allows us to be sure that any
     // property changes that occur as a result of binding will be observed.
     if (!_elementPrepared) prepareElement();
@@ -429,23 +461,27 @@
     var property = propertyForAttribute(name);
     if (property == null) {
       // Cannot call super.bind because template_binding is its own package
-      return nodeBindFallback(this).bind(name, model, path);
+      return nodeBindFallback(this).bind(name, bindable, oneTime: oneTime);
     } else {
       // clean out the closets
       unbind(name);
       // use n-way Polymer binding
-      var observer = bindProperty(property.simpleName, model, path);
+      var observer = bindProperty(property.simpleName, bindable);
+
       // reflect bound property to attribute when binding
       // to ensure binding is not left on attribute if property
       // does not update due to not changing.
       // Dart note: we include this patch:
       // https://github.com/Polymer/polymer/pull/319
-      reflectPropertyToAttribute(property.simpleName);
+
+      // TODO(jmesserly): polymer has the path_ in their observer object, should
+      // we use that too instead of allocating it here?
+      reflectPropertyToAttribute(new PropertyPath([property.simpleName]));
       return bindings[name] = observer;
     }
   }
 
-  Map<String, NodeBinding> get bindings => nodeBindFallback(this).bindings;
+  Map<String, Bindable> get bindings => nodeBindFallback(this).bindings;
   TemplateInstance get templateInstance =>
       nodeBindFallback(this).templateInstance;
 
@@ -508,65 +544,72 @@
 
   /** Set up property observers. */
   void observeProperties() {
-    // TODO(jmesserly): we don't have CompoundPathObserver, so this
-    // implementation is a little bit different. We also don't expose the
-    // "generateCompoundPathObserver" method.
     final observe = _declaration._observe;
     final publish = _declaration._publish;
 
-    if (observe != null) {
-      for (var name in observe.keys) {
-        observeArrayValue(name, reflect(this).getField(name), null);
+    // TODO(jmesserly): workaround for a dart2js compiler bug
+    bool hasObserved = observe != null;
+
+    if (hasObserved || publish != null) {
+      var o = _propertyObserver = new CompoundObserver();
+      if (hasObserved) {
+        for (var path in observe.keys) {
+          o.addPath(this, path);
+
+          // TODO(jmesserly): on the Polymer side it doesn't look like they
+          // will observe arrays unless it is a length == 1 path.
+          observeArrayValue(path, path.getValueFrom(this), null);
+        }
       }
-    }
-    if (observe != null || publish != null) {
-      // Instead of using CompoundPathObserver, set up a binding using normal
-      // change records.
-      _propertyObserver = changes.listen(notifyPropertyChanges);
+      if (publish != null) {
+        for (var path in publish.keys) {
+
+          if (!hasObserved || !observe.containsKey(path)) {
+            o.addPath(this, path);
+          }
+        }
+      }
+      o.open(notifyPropertyChanges);
     }
   }
 
+
   /** Responds to property changes on this element. */
-  // Dart note: this takes a list of changes rather than trying to deal with
-  // what CompoundPathObserver would give us. Simpler and probably faster too.
-  void notifyPropertyChanges(Iterable<ChangeRecord> changes) {
+  void notifyPropertyChanges(List newValues, Map oldValues, List paths) {
     final observe = _declaration._observe;
     final publish = _declaration._publish;
+    final called = new HashSet();
 
-    // Summarize old and new values, so we only handle each change once.
-    final valuePairs = new Map<Symbol, _PropertyValue>();
-    for (var c in changes) {
-      if (c is! PropertyChangeRecord) continue;
-
-      valuePairs.putIfAbsent(c.name, () => new _PropertyValue(c.oldValue))
-          .newValue = c.newValue;
-    }
-
-    valuePairs.forEach((name, pair) {
-      if (publish != null && publish.containsKey(name)) {
-        reflectPropertyToAttribute(name);
+    oldValues.forEach((i, oldValue) {
+      // note: paths is of form [object, path, object, path]
+      var path = paths[2 * i + 1];
+      if (publish != null && publish.containsKey(path)) {
+        reflectPropertyToAttribute(path);
       }
       if (observe == null) return;
 
-      var method = observe[name];
-      if (method != null) {
+      var methods = observe[path];
+      if (methods == null) return;
+
+      for (var method in methods) {
+        if (!called.add(method)) continue; // don't invoke more than once.
+
+        final newValue = newValues[i];
         // observes the value if it is an array
-        observeArrayValue(name, pair.newValue, pair.oldValue);
-        // TODO(jmesserly): the JS code tries to avoid calling the same method
-        // twice, but I don't see how that is possible.
-        // Dart note: JS also passes "arguments", so we pass all change records.
-        invokeMethod(method, [pair.oldValue, pair.newValue, changes]);
+        observeArrayValue(path, newValue, oldValue);
+        // Dart note: JS passes "arguments", so we pass along our args.
+        invokeMethod(method, [oldValue, newValue, newValues, oldValues, paths]);
       }
     });
   }
 
-  void observeArrayValue(Symbol name, Object value, Object old) {
+  void observeArrayValue(PropertyPath name, Object value, Object old) {
     final observe = _declaration._observe;
     if (observe == null) return;
 
     // we only care if there are registered side-effects
-    var callbackName = observe[name];
-    if (callbackName == null) return;
+    var callbacks = observe[name];
+    if (callbacks == null) return;
 
     // if we are observing the previous value, stop
     if (old is ObservableList) {
@@ -575,7 +618,7 @@
             '$name');
       }
 
-      unregisterObserver('${MirrorSystem.getName(name)}__array');
+      unregisterObserver('${name}__array');
     }
     // if the new value is an array, being observing it
     if (value is ObservableList) {
@@ -584,9 +627,11 @@
             '$name');
       }
       var sub = value.listChanges.listen((changes) {
-        invokeMethod(callbackName, [old]);
+        for (var callback in callbacks) {
+          invokeMethod(callback, [old]);
+        }
       });
-      registerObserver('${MirrorSystem.getName(name)}__array', sub);
+      registerObserver('${name}__array', sub);
     }
   }
 
@@ -594,7 +639,7 @@
 
   void unbindAllProperties() {
     if (_propertyObserver != null) {
-      _propertyObserver.cancel();
+      _propertyObserver.close();
       _propertyObserver = null;
     }
     unregisterObservers();
@@ -633,37 +678,29 @@
    *       bindProperty(#myProperty, this, 'myModel.path.to.otherProp');
    *     }
    */
-  // TODO(jmesserly): replace with something more localized, like:
-  // @ComputedField('myModel.path.to.otherProp');
-  NodeBinding bindProperty(Symbol name, Object model, [String path]) =>
-      // apply Polymer two-way reference binding
-      _bindProperties(this, name, model, path);
-
-  /**
-   * bind a property in A to a path in B by converting A[property] to a
-   * getter/setter pair that accesses B[...path...]
-   */
-  static NodeBinding _bindProperties(Polymer inA, Symbol inProperty,
-        Object inB, String inPath) {
-
-    if (_bindLog.isLoggable(Level.FINE)) {
-      _bindLog.fine('[$inB]: bindProperties: [$inPath] to '
-          '[${inA.localName}].[$inProperty]');
-    }
-
+  Bindable bindProperty(Symbol name, Bindable bindable) {
     // Dart note: normally we only reach this code when we know it's a
     // property, but if someone uses bindProperty directly they might get a
     // NoSuchMethodError either from the getField below, or from the setField
     // inside PolymerBinding. That doesn't seem unreasonable, but it's a slight
     // difference from Polymer.js behavior.
 
+    if (_bindLog.isLoggable(Level.FINE)) {
+      _bindLog.fine('bindProperty: [$bindable] to [${localName}].[name]');
+    }
+
     // capture A's value if B's value is null or undefined,
     // otherwise use B's value
-    var path = new PathObserver(inB, inPath);
-    if (path.value == null) {
-      path.value = reflect(inA).getField(inProperty).reflectee;
+    // TODO(sorvell): need to review, can do with ObserverTransform
+    var v = bindable.value;
+    if (v == null) {
+      bindable.value = reflect(this).getField(name).reflectee;
     }
-    return new _PolymerBinding(inA, inProperty, inB, inPath);
+
+    // TODO(jmesserly): this will create another subscription.
+    // It would be nice to have this reuse our existing _propertyObserver
+    // created by observeProperties, to avoid more observation overhead.
+    return new _PolymerBinding(this, name, bindable);
   }
 
   /** Attach event listeners on the host (this) element. */
@@ -702,8 +739,7 @@
     var h = findEventDelegate(event);
     if (h != null) {
       if (log) _eventsLog.fine('[$localName] found host handler name [$h]');
-      var detail = event is CustomEvent ?
-          (event as CustomEvent).detail : null;
+      var detail = event is CustomEvent ? event.detail : null;
       // TODO(jmesserly): cache the symbols?
       dispatchMethod(this, h, [event, detail, this]);
     }
@@ -745,16 +781,10 @@
    * the bound path at event execution time.
    */
   // from src/instance/event.js#prepareBinding
-  // TODO(sorvell): we're patching the syntax while evaluating
-  // event bindings. we'll move this to a better spot when that's done
-  static PrepareBindingFunction prepareBinding(String path, String name, node,
-      originalPrepareBinding) {
-
-    // if lhs an event prefix,
-    if (!_hasEventPrefix(name)) return originalPrepareBinding(path, name, node);
+  static PrepareBindingFunction prepareBinding(String path, String name, node) {
 
     // provide an event-binding callback.
-    return (model, node) {
+    return (model, node, oneTime) {
       if (_eventsLog.isLoggable(Level.FINE)) {
         _eventsLog.fine('event: [$node].$name => [$model].$path())');
       }
@@ -763,46 +793,17 @@
       var translated = _eventTranslations[eventName];
       eventName = translated != null ? translated : eventName;
 
-      // TODO(jmesserly): we need a place to unregister this. See:
-      // https://code.google.com/p/dart/issues/detail?id=15574
-      node.on[eventName].listen((event) {
-        var ctrlr = _findController(node);
-        if (ctrlr is! Polymer) return;
-        var obj = ctrlr;
-        var method = path;
-        if (path[0] == '@') {
-          obj = model;
-          method = new PathObserver(model, path.substring(1)).value;
-        }
-        var detail = event is CustomEvent ?
-            (event as CustomEvent).detail : null;
-        ctrlr.dispatchMethod(obj, method, [event, detail, node]);
-      });
-
-      // TODO(jmesserly): this return value is bogus. Returning null here causes
-      // the wrong thing to happen in template_binding.
-      return new ObservableBox();
+      return new _EventBindable(node, eventName, model, path);
     };
   }
 
-  // TODO(jmesserly): this won't find the correct host unless the ShadowRoot
-  // was created on a PolymerElement.
-  static Polymer _findController(Node node) {
-    while (node.parentNode != null) {
-      node = node.parentNode;
-    }
-    return _shadowHost[node];
-  }
-
   /** Call [methodName] method on this object with [args]. */
   invokeMethod(Symbol methodName, List args) =>
       _invokeMethod(this, methodName, args);
 
   /** Call [methodName] method on [receiver] with [args]. */
   static _invokeMethod(receiver, Symbol methodName, List args) {
-    // TODO(sigmund): consider making callbacks list all arguments
-    // explicitly. Unless VM mirrors are optimized first, this will be expensive
-    // once custom elements extend directly from Element (see issue 11108).
+    // TODO(jmesserly): use function type tests instead of mirrors for dispatch.
     var receiverMirror = reflect(receiver);
     var method = _findMethod(receiverMirror.type, methodName);
     if (method != null) {
@@ -999,27 +1000,21 @@
 // listen to changes on both sides and update the values.
 // TODO(jmesserly): our approach leads to race conditions in the bindings.
 // See http://code.google.com/p/dart/issues/detail?id=13567
-class _PolymerBinding extends NodeBinding {
+class _PolymerBinding extends Bindable {
   final InstanceMirror _target;
   final Symbol _property;
+  final Bindable _bindable;
   StreamSubscription _sub;
   Object _lastValue;
 
-  _PolymerBinding(Polymer node, Symbol property, model, path)
-      : _target = reflect(node),
-        _property = property,
-        super(node, MirrorSystem.getName(property), model, path) {
+  _PolymerBinding(Polymer node, this._property, this._bindable)
+      : _target = reflect(node) {
 
     _sub = node.changes.listen(_propertyValueChanged);
+    _updateNode(open(_updateNode));
   }
 
-  void close() {
-    if (closed) return;
-    _sub.cancel();
-    super.close();
-  }
-
-  void valueChanged(newValue) {
+  void _updateNode(newValue) {
     _lastValue = newValue;
     _target.setField(_property, newValue);
   }
@@ -1029,19 +1024,30 @@
       if (record is PropertyChangeRecord && record.name == _property) {
         final newValue = _target.getField(_property).reflectee;
         if (!identical(_lastValue, newValue)) {
-          value = newValue;
+          this.value = newValue;
         }
         return;
       }
     }
   }
+
+  open(callback(value)) => _bindable.open(callback);
+  get value => _bindable.value;
+  set value(newValue) => _bindable.value = newValue;
+
+  void close() {
+    if (_sub != null) {
+      _sub.cancel();
+      _sub = null;
+    }
+    _bindable.close();
+  }
 }
 
 bool _toBoolean(value) => null != value && false != value;
 
 TypeMirror _propertyType(DeclarationMirror property) =>
-    property is VariableMirror
-        ? (property as VariableMirror).type
+    property is VariableMirror ? property.type
         : (property as MethodMirror).returnType;
 
 TypeMirror _inferPropertyType(Object value, DeclarationMirror property) {
@@ -1095,6 +1101,58 @@
 }
 
 class _PolymerExpressionsWithEventDelegate extends PolymerExpressions {
-  prepareBinding(String path, name, node) =>
-      Polymer.prepareBinding(path, name, node, super.prepareBinding);
+  prepareBinding(String path, name, node) {
+    if (_hasEventPrefix(name)) return Polymer.prepareBinding(path, name, node);
+    return super.prepareBinding(path, name, node);
+  }
 }
+
+class _EventBindable extends Bindable {
+  final Node _node;
+  final String _eventName;
+  final _model;
+  final String _path;
+  StreamSubscription _sub;
+
+  _EventBindable(this._node, this._eventName, this._model, this._path);
+
+  _listener(event) {
+    var ctrlr = _findController(_node);
+    if (ctrlr is! Polymer) return;
+    var obj = ctrlr;
+    var method = _path;
+    if (_path.startsWith('@')) {
+      obj = _model;
+      method = new PropertyPath(_path.substring(1)).getValueFrom(_model);
+    }
+    var detail = event is CustomEvent ?
+        (event as CustomEvent).detail : null;
+    ctrlr.dispatchMethod(obj, method, [event, detail, _node]);
+  }
+
+  // TODO(jmesserly): this won't find the correct host unless the ShadowRoot
+  // was created on a PolymerElement.
+  static Polymer _findController(Node node) {
+    while (node.parentNode != null) {
+      node = node.parentNode;
+    }
+    return _shadowHost[node];
+  }
+
+  get value => null;
+
+  open(callback) {
+    _sub = _node.on[_eventName].listen(_listener);
+  }
+
+  close() {
+    if (_sub != null) {
+      if (_eventsLog.isLoggable(Level.FINE)) {
+        _eventsLog.fine(
+            'event.remove: [$_node].$_eventName => [$_model].$_path())');
+      }
+     _sub.cancel();
+      _sub = null;
+    }
+  }
+}
\ No newline at end of file
diff --git a/pkg/polymer/lib/src/loader.dart b/pkg/polymer/lib/src/loader.dart
index 28adf3d..7a04ef1 100644
--- a/pkg/polymer/lib/src/loader.dart
+++ b/pkg/polymer/lib/src/loader.dart
@@ -21,78 +21,88 @@
  *   * set up up polling for observable changes
  *   * initialize Model-Driven Views
  *   * Include some style to prevent flash of unstyled content (FOUC)
- *   * for each library in [libraries], register custom elements labeled with
- *      [CustomTag] and invoke the initialization method on it. If [libraries]
- *      is null, first find all libraries that need to be loaded by scanning for
- *      HTML imports in the main document.
- *
- * The initialization on each library is a top-level function and annotated with
- * [initMethod].
- *
- * The urls in [libraries] can be absolute or relative to
- * `currentMirrorSystem().isolate.rootLibrary.uri`.
+ *   * for each library included transitively from HTML and HTML imports,
+ *   register custom elements declared there (labeled with [CustomTag]) and
+ *   invoke the initialization method on it (top-level functions annotated with
+ *   [initMethod]).
  */
 Zone initPolymer() {
+  // We use this pattern, and not the inline lazy initialization pattern, so we
+  // can help dart2js detect that _discoverInitializers can be tree-shaken for
+  // deployment (and hence all uses of dart:mirrors from this loading logic).
+  // TODO(sigmund): fix polymer's transformers so they can replace initPolymer
+  // by initPolymerOptimized.
+  if (_initializers == null) _initializers = _discoverInitializers();
   if (_useDirtyChecking) {
-    return dirtyCheckZone()..run(_initPolymerOptimized);
+    return dirtyCheckZone()..run(initPolymerOptimized);
   }
 
-  _initPolymerOptimized();
-  return Zone.current;
+  return initPolymerOptimized();
 }
 
 /**
  * Same as [initPolymer], but runs the version that is optimized for deployment
  * to the internet. The biggest difference is it omits the [Zone] that
- * automatically invokes [Observable.dirtyCheck], and the list of libraries must
- * be supplied instead of being dynamically searched for at runtime.
+ * automatically invokes [Observable.dirtyCheck], and the list of initializers
+ * must be supplied instead of being dynamically searched for at runtime using
+ * mirrors.
  */
-// TODO(jmesserly): change the Polymer build step to call this directly.
-void _initPolymerOptimized() {
+Zone initPolymerOptimized() {
+  // TODO(jmesserly): there is some code in src/declaration/polymer-element.js,
+  // git version 37eea00e13b9f86ab21c85a955585e8e4237e3d2, right before
+  // it registers polymer-element, which uses Platform.deliverDeclarations to
+  // coordinate with HTML Imports. I don't think we need it so skipping.
   document.register(PolymerDeclaration._TAG, PolymerDeclaration);
 
-  _loadLibraries();
+  for (var initializer in _initializers) {
+    initializer();
+  }
 
   // Run this after user code so they can add to Polymer.veiledElements
   _preventFlashOfUnstyledContent();
 
   customElementsReady.then((_) => Polymer._ready.complete());
+  return Zone.current;
 }
 
 /**
  * Configures [initPolymer] making it optimized for deployment to the internet.
- * With this setup the list of libraries to initialize is supplied instead of
- * being dynamically searched for at runtime. Additionally, after this method is
- * called, [initPolymer] omits the [Zone] that automatically invokes
+ * With this setup the initializer list is supplied instead of being dynamically
+ * searched for at runtime. Additionally, after this method is called,
+ * [initPolymer] omits the [Zone] that automatically invokes
  * [Observable.dirtyCheck].
  */
-void configureForDeployment(List<String> libraries) {
-  _librariesToLoad = libraries;
+void configureForDeployment(List<Function> initializers) {
+  _initializers = initializers;
   _useDirtyChecking = false;
 }
 
 /**
- * Libraries that will be initialized. For each library, the intialization
- * registers any type tagged with a [CustomTag] annotation and calls any
+ * List of initializers that by default will be executed when calling
+ * initPolymer. If null, initPolymer will compute the list of initializers by
+ * crawling HTML imports, searchfing for script tags, and including an
+ * initializer for each type tagged with a [CustomTag] annotation and for each
  * top-level method annotated with [initMethod]. The value of this field is
  * assigned programatically by the code generated from the polymer deploy
- * scripts. During development, the libraries are inferred by crawling HTML
- * imports and searching for script tags.
+ * scripts.
  */
-List<String> _librariesToLoad =
-    _discoverScripts(document, window.location.href);
+List<Function> _initializers;
+
 bool _useDirtyChecking = true;
 
-void _loadLibraries() {
-  for (var lib in _librariesToLoad) {
+List<Function> _discoverInitializers() {
+  var initializers = [];
+  var librariesToLoad = _discoverScripts(document, window.location.href);
+  for (var lib in librariesToLoad) {
     try {
-      _loadLibrary(lib);
+      _loadLibrary(lib, initializers);
     } catch (e, s) {
       // Deliver errors async, so if a single library fails it doesn't prevent
       // other things from loading.
       new Completer().completeError(e, s);
     }
   }
+  return initializers;
 }
 
 /**
@@ -159,7 +169,7 @@
  *   * Registers any [PolymerElement] that is marked with the [CustomTag]
  *     annotation.
  */
-void _loadLibrary(String uriString) {
+void _loadLibrary(String uriString, List<Function> initializers) {
   var uri = _rootUri.resolve(uriString);
   var lib = _libs[uri];
   if (_isHttpStylePackageUrl(uri)) {
@@ -185,7 +195,7 @@
 
   // Search top-level functions marked with @initMethod
   for (var f in lib.declarations.values.where((d) => d is MethodMirror)) {
-    _maybeInvoke(lib, f);
+    _addInitMethod(lib, f, initializers);
   }
 
   for (var c in lib.declarations.values.where((d) => d is ClassMirror)) {
@@ -193,7 +203,7 @@
     for (var m in c.metadata) {
       var meta = m.reflectee;
       if (meta is CustomTag) {
-        Polymer.register(meta.tagName, c.reflectedType);
+        initializers.add(() => Polymer.register(meta.tagName, c.reflectedType));
       }
     }
 
@@ -206,7 +216,8 @@
   }
 }
 
-void _maybeInvoke(ObjectMirror obj, MethodMirror method) {
+void _addInitMethod(ObjectMirror obj, MethodMirror method,
+    List<Function> initializers) {
   var annotationFound = false;
   for (var meta in method.metadata) {
     if (identical(meta.reflectee, initMethod)) {
@@ -225,7 +236,7 @@
         "arguments, ${method.simpleName} expects some.");
     return;
   }
-  obj.invoke(method.simpleName, const []);
+  initializers.add(() => obj.invoke(method.simpleName, const []));
 }
 
 class _InitMethodAnnotation {
diff --git a/pkg/polymer/pubspec.yaml b/pkg/polymer/pubspec.yaml
index 7a3ab81..15475869 100644
--- a/pkg/polymer/pubspec.yaml
+++ b/pkg/polymer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: polymer
-version: 0.9.5-dev
+version: 0.10.0-dev
 author: Polymer.dart Authors <web-ui-dev@dartlang.org>
 description: >
   Polymer.dart is a new type of library for the web, built on top of Web
diff --git a/pkg/polymer/test/attr_mustache_test.dart b/pkg/polymer/test/attr_mustache_test.dart
index 8f2cae1..45da525 100644
--- a/pkg/polymer/test/attr_mustache_test.dart
+++ b/pkg/polymer/test/attr_mustache_test.dart
@@ -17,8 +17,8 @@
   Future get foundSrc => _found.future;
 
   // force an mdv binding
-  bind(name, model, [path]) =>
-      nodeBindFallback(this).bind(name, model, path);
+  bind(name, value, {oneTime: false}) =>
+      nodeBindFallback(this).bind(name, value, oneTime: oneTime);
 
   inserted() {
     testSrcForMustache();
diff --git a/pkg/polymer/test/build/all_phases_test.dart b/pkg/polymer/test/build/all_phases_test.dart
index bb39a85..3f84593 100644
--- a/pkg/polymer/test/build/all_phases_test.dart
+++ b/pkg/polymer/test/build/all_phases_test.dart
@@ -49,7 +49,6 @@
 
           void main() {
             configureForDeployment([
-                'a.dart',
               ]);
             i0.main();
           }
@@ -77,7 +76,6 @@
 
           void main() {
             configureForDeployment([
-                'test.html.0.dart',
               ]);
             i0.main();
           }
@@ -119,7 +117,6 @@
 
           void main() {
             configureForDeployment([
-                'a.dart',
               ]);
             i0.main();
           }
@@ -158,8 +155,6 @@
 
           void main() {
             configureForDeployment([
-                'test2.html.0.dart',
-                'b.dart',
               ]);
             i1.main();
           }
diff --git a/pkg/polymer/test/build/script_compactor_test.dart b/pkg/polymer/test/build/script_compactor_test.dart
index e3ec79c..2d32a74 100644
--- a/pkg/polymer/test/build/script_compactor_test.dart
+++ b/pkg/polymer/test/build/script_compactor_test.dart
@@ -50,7 +50,6 @@
 
           void main() {
             configureForDeployment([
-                'a.dart',
               ]);
             i0.main();
           }
@@ -66,7 +65,52 @@
           '</div>',
       'a|web/test.html.scriptUrls':
           '[["a", "web/a.dart"],["a", "web/b.dart"],["a", "web/c.dart"]]',
-      'a|web/d.dart': 'library d;\nmain(){}',
+      'a|web/d.dart': 'library d;\nmain(){}\n@initMethod mD(){}',
+
+      'a|web/a.dart':
+          'import "package:polymer/polymer.dart";\n'
+          '@initMethod mA(){}\n',
+
+      'a|web/b.dart':
+          'export "e.dart";\n'
+          'export "f.dart" show XF1, mF1;\n'
+          'export "g.dart" hide XG1, mG1;\n'
+          'export "h.dart" show XH1, mH1 hide mH1, mH2;\n'
+          '@initMethod mB(){}\n',
+
+      'a|web/c.dart':
+          'import "package:polymer/polymer.dart";\n'
+          'part "c_part.dart"\n'
+          '@CustomTag("x-c2") class XC2 {}\n',
+
+      'a|web/c_part.dart':
+          '@CustomTag("x-c1") class XC1 {}\n',
+
+      'a|web/e.dart':
+          'import "package:polymer/polymer.dart";\n'
+          '@CustomTag("x-e") class XE {}\n'
+          '@initMethod mE(){}\n',
+
+      'a|web/f.dart':
+          'import "package:polymer/polymer.dart";\n'
+          '@CustomTag("x-f1") class XF1 {}\n'
+          '@initMethod mF1(){}\n'
+          '@CustomTag("x-f2") class XF2 {}\n'
+          '@initMethod mF2(){}\n',
+
+      'a|web/g.dart':
+          'import "package:polymer/polymer.dart";\n'
+          '@CustomTag("x-g1") class XG1 {}\n'
+          '@initMethod mG1(){}\n'
+          '@CustomTag("x-g2") class XG2 {}\n'
+          '@initMethod mG2(){}\n',
+
+      'a|web/h.dart':
+          'import "package:polymer/polymer.dart";\n'
+          '@CustomTag("x-h1") class XH1 {}\n'
+          '@initMethod mH1(){}\n'
+          '@CustomTag("x-h2") class XH2 {}\n'
+          '@initMethod mH2(){}\n',
     }, {
       'a|web/test.html':
           '<!DOCTYPE html><html><head></head><body><div>'
@@ -84,10 +128,18 @@
 
           void main() {
             configureForDeployment([
-                'a.dart',
-                'b.dart',
-                'c.dart',
-                'd.dart',
+                i0.mA,
+                () => Polymer.register('x-e', i1.XE),
+                i1.mE,
+                () => Polymer.register('x-f1', i1.XF1),
+                i1.mF1,
+                () => Polymer.register('x-g2', i1.XG2),
+                i1.mG2,
+                () => Polymer.register('x-h1', i1.XH1),
+                i1.mB,
+                () => Polymer.register('x-c1', i2.XC1),
+                () => Polymer.register('x-c2', i2.XC2),
+                i3.mD,
               ]);
             i3.main();
           }
diff --git a/pkg/polymer/test/custom_event_test.dart b/pkg/polymer/test/custom_event_test.dart
index eef68e0..08c45af 100644
--- a/pkg/polymer/test/custom_event_test.dart
+++ b/pkg/polymer/test/custom_event_test.dart
@@ -53,10 +53,10 @@
     final fooBar = testComp.fooBar;
 
     final binding = nodeBind(fooBar).bindings['on-barbaz'];
-    expect(binding, isNotNull, reason: 'on-barbaz event should be bound');
+    expect(binding is Bindable, true,
+        reason: 'on-barbaz event should be bound');
 
-    expect(binding.model is! StreamSubscription, true,
-        reason: 'event bindings should not be a StreamSubscription');
+    expect(binding.value, null, reason: 'event bindings do not have value');
 
     fooBar.fireFoo(123);
     fooBar.fireBarBaz(42);
diff --git a/pkg/polymer/test/event_handlers_test.dart b/pkg/polymer/test/event_handlers_test.dart
index 0b65bf6..33d8631 100644
--- a/pkg/polymer/test/event_handlers_test.dart
+++ b/pkg/polymer/test/event_handlers_test.dart
@@ -109,7 +109,7 @@
   initPolymer();
 }
 
-@initMethod _init() {
+@initMethod init() {
   useHtmlConfiguration();
 
   setUp(() => Polymer.onReady);
diff --git a/pkg/polymer/test/event_path_declarative_test.dart b/pkg/polymer/test/event_path_declarative_test.dart
index a96779a..1c9495f 100644
--- a/pkg/polymer/test/event_path_declarative_test.dart
+++ b/pkg/polymer/test/event_path_declarative_test.dart
@@ -81,7 +81,7 @@
   }
 }
 
-@initMethod _init() {
+@initMethod init() {
   useHtmlConfiguration();
   // TODO(sigmund): switch back to use @CustomTag. We seem to be running into a
   // problem where using @CustomTag doesn't guarantee that we register the tags
diff --git a/pkg/polymer/test/nested_binding_test.dart b/pkg/polymer/test/nested_binding_test.dart
index ab991d9..f4c4959 100644
--- a/pkg/polymer/test/nested_binding_test.dart
+++ b/pkg/polymer/test/nested_binding_test.dart
@@ -35,5 +35,6 @@
 
   setUp(() => Polymer.onReady);
 
-  test('ready called', () => (query('my-test') as MyTest)._testDone.future);
+  test('ready called',
+      () => (querySelector('my-test') as MyTest)._testDone.future);
 }
diff --git a/pkg/polymer/test/property_observe_test.dart b/pkg/polymer/test/property_observe_test.dart
new file mode 100644
index 0000000..c3facc6
--- /dev/null
+++ b/pkg/polymer/test/property_observe_test.dart
@@ -0,0 +1,91 @@
+// 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.
+
+library polymer.test.property_change_test;
+
+import 'dart:async';
+import 'dart:html';
+import 'package:polymer/polymer.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'package:unittest/matcher.dart';
+
+var _changes = 0;
+final _done = new Completer();
+
+checkDone() {
+  if (6 == ++_changes) {
+    _done.complete();
+  }
+}
+
+@CustomTag('x-test')
+class XTest extends PolymerElement {
+  @observable String bar = '';
+  @observable String pie;
+  @observable Map a;
+
+  XTest.created() : super.created();
+
+  ready() {
+    bar = 'bar';
+    pie = 'pie';
+    a = {'b': {'c': 'exists'}};
+  }
+
+  barChanged() {
+    // Dart note: unlike polymer-js we support multiple observers, due to how
+    // our @ObserveProperty metadata translated.
+    // _done.completeError('barChanged should not be called.');
+    expect('bar', 'bar', reason: 'barChanged called');
+    checkDone();
+  }
+
+  @ObserveProperty('bar pie')
+  validate() {
+    window.console.log('validate');
+    expect('bar', 'bar', reason: 'custom change observer called');
+    expect('pie', 'pie', reason: 'custom change observer called');
+    checkDone();
+  }
+
+  // Dart note: test that we can observe "pie" twice.
+  @ObserveProperty('pie')
+  validateYummyPie() {
+    window.console.log('validateYummyPie');
+    expect('pie', 'pie', reason: 'validateYummyPie called');
+    checkDone();
+  }
+
+
+  @ObserveProperty('a.b.c')
+  validateSubPath(oldValue, newValue) {
+    window.console.log('validateSubPath $oldValue $newValue');
+    expect(newValue, 'exists', reason: 'subpath change observer called');
+    checkDone();
+  }
+}
+
+@CustomTag('x-test2')
+class XTest2 extends XTest {
+  @observable String noogle;
+
+  XTest2.created() : super.created();
+
+  @ObserveProperty('noogle')
+  validate() => super.validate();
+
+  ready() {
+    super.ready();
+    noogle = 'noogle';
+  }
+}
+
+main() => initPolymer().run(() {
+  useHtmlConfiguration();
+
+  setUp(() => Polymer.onReady);
+
+  test('changes detected', () => _done.future);
+});
diff --git a/pkg/polymer/test/property_observe_test.html b/pkg/polymer/test/property_observe_test.html
new file mode 100644
index 0000000..a71228e
--- /dev/null
+++ b/pkg/polymer/test/property_observe_test.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<!--
+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.
+-->
+<html>
+  <!--polymer-test: this comment is needed for test_suite.dart-->
+  <head>
+    <title>property.observe changes</title>
+    <script src="/root_dart/tools/testing/dart/test_controller.js"></script>
+  </head>
+  <body>
+    <x-test id="test"></x-test>
+    <x-test2 id="test"></x-test2>
+
+    <polymer-element name="x-test"><template></template></polymer-element>
+    <polymer-element name="x-test2" extends="x-test">
+      <template></template>
+    </polymer-element>
+    <script type="application/dart" src="property_observe_test.dart"></script>
+  </body>
+</html>
diff --git a/pkg/polymer/test/publish_attributes_test.dart b/pkg/polymer/test/publish_attributes_test.dart
index 8701a7b..78bd593 100644
--- a/pkg/polymer/test/publish_attributes_test.dart
+++ b/pkg/polymer/test/publish_attributes_test.dart
@@ -62,10 +62,10 @@
     published(tag) => (query('polymer-element[name=$tag]')
         as PolymerDeclaration).publishedProperties;
 
-    expect(published('x-foo'), [#Foo, #baz]);
-    expect(published('x-bar'), [#Foo, #baz, #Bar]);
-    expect(published('x-zot'), [#Foo, #baz, #Bar, #zot]);
-    expect(published('x-squid'), [#Foo, #baz, #Bar, #zot, #squid]);
-    expect(published('x-qux'), [#qux]);
+    expect(published('x-foo'), ['Foo', 'baz']);
+    expect(published('x-bar'), ['Foo', 'baz', 'Bar']);
+    expect(published('x-zot'), ['Foo', 'baz', 'Bar', 'zot']);
+    expect(published('x-squid'), ['Foo', 'baz', 'Bar', 'zot', 'squid']);
+    expect(published('x-qux'), ['qux']);
   });
 }
diff --git a/pkg/polymer/test/publish_inherited_properties_test.dart b/pkg/polymer/test/publish_inherited_properties_test.dart
index 7eec80a..24595c4 100644
--- a/pkg/polymer/test/publish_inherited_properties_test.dart
+++ b/pkg/polymer/test/publish_inherited_properties_test.dart
@@ -56,9 +56,9 @@
     published(tag) => (query('polymer-element[name=$tag]')
         as PolymerDeclaration).publishedProperties;
 
-    expect(published('x-zot'), [#Foo, #Bar, #zot, #m]);
-    expect(published('x-squid'), [#Foo, #Bar, #zot, #m, #baz, #squid]);
-    expect(published('x-noscript'), [#Foo, #Bar, #zot, #m]);
+    expect(published('x-zot'), ['Foo', 'Bar', 'zot', 'm']);
+    expect(published('x-squid'), ['Foo', 'Bar', 'zot', 'm', 'baz', 'squid']);
+    expect(published('x-noscript'), ['Foo', 'Bar', 'zot', 'm']);
     // TODO(sigmund): uncomment, see above
     // expect(published('x-squid'), [#Foo, #Bar, #zot, #zap, #baz, #squid]);
   });
diff --git a/pkg/polymer_expressions/example/streams/collect_key_press.html b/pkg/polymer_expressions/example/streams/collect_key_press.html
index 0bd7ffe..d2225f5 100644
--- a/pkg/polymer_expressions/example/streams/collect_key_press.html
+++ b/pkg/polymer_expressions/example/streams/collect_key_press.html
@@ -31,7 +31,7 @@
           'collect': collect,
         };
 
-        templateBind(query('#test'))
+        templateBind(querySelector('#test'))
             ..bindingDelegate = new PolymerExpressions(globals: globals)
             ..model = null;
       }
diff --git a/pkg/polymer_expressions/lib/eval.dart b/pkg/polymer_expressions/lib/eval.dart
index be2fdec..22851e6 100644
--- a/pkg/polymer_expressions/lib/eval.dart
+++ b/pkg/polymer_expressions/lib/eval.dart
@@ -249,6 +249,8 @@
 
   ExpressionObserver(this._expr);
 
+  Expression get expression => _expr;
+
   Object get currentValue => _value;
 
   update(Scope scope) => _updateSelf(scope);
diff --git a/pkg/polymer_expressions/lib/polymer_expressions.dart b/pkg/polymer_expressions/lib/polymer_expressions.dart
index 0d4d061..36ea352 100644
--- a/pkg/polymer_expressions/lib/polymer_expressions.dart
+++ b/pkg/polymer_expressions/lib/polymer_expressions.dart
@@ -81,17 +81,23 @@
       return null;
     }
 
-    return (model, node) {
+    return (model, node, oneTime) {
       if (model is! Scope) {
         model = new Scope(model: model, variables: globals);
       }
+      var converter = null;
       if (node is Element && name == "class") {
-        return new _Binding(expr, model, _classAttributeConverter);
+        converter = _classAttributeConverter;
       }
       if (node is Element && name == "style") {
-        return new _Binding(expr, model, _styleAttributeConverter);
+        converter = _styleAttributeConverter;
       }
-      return new _Binding(expr, model);
+
+      if (oneTime) {
+        return _Binding._oneTime(expr, model, converter);
+      }
+
+      return new _Binding(expr, model, converter);
     };
   }
 
@@ -99,50 +105,82 @@
       model is Scope ? model : new Scope(model: model, variables: globals);
 }
 
-class _Binding extends ChangeNotifier {
+class _Binding extends Bindable {
   final Scope _scope;
-  final ExpressionObserver _expr;
   final _converter;
+  Expression _expr;
+  Function _callback;
+  StreamSubscription _sub;
   var _value;
 
-  _Binding(Expression expr, Scope scope, [this._converter])
-      : _expr = observe(expr, scope),
-        _scope = scope {
-    _expr.onUpdate.listen(_setValue).onError((e) {
-      _logger.warning("Error evaluating expression '$_expr': ${e.message}");
-    });
+  _Binding(this._expr, this._scope, [this._converter]);
+
+  static _oneTime(Expression expr, Scope scope, [converter]) {
     try {
-      update(_expr, _scope);
-      _setValue(_expr.currentValue);
+      return _convertValue(eval(expr, scope), scope, converter);
     } on EvalException catch (e) {
-      _logger.warning("Error evaluating expression '$_expr': ${e.message}");
+      _logger.warning("Error evaluating expression '$expr': ${e.message}");
+      return null;
     }
   }
 
   _setValue(v) {
-    var oldValue = _value;
+    _value = _convertValue(v, _scope, _converter);
+    if (_callback != null) _callback(_value);
+  }
+
+  static _convertValue(v, scope, converter) {
     if (v is Comprehension) {
       // convert the Comprehension into a list of scopes with the loop
       // variable added to the scope
-      _value = v.iterable.map((i) {
+      return v.iterable.map((i) {
         var vars = new Map();
         vars[v.identifier] = i;
-        Scope childScope = new Scope(parent: _scope, variables: vars);
+        Scope childScope = new Scope(parent: scope, variables: vars);
         return childScope;
       }).toList(growable: false);
     } else {
-      _value = (_converter == null) ? v : _converter(v);
+      return converter == null ? v : converter(v);
     }
-    notifyPropertyChange(#value, oldValue, _value);
   }
 
-  @reflectable get value => _value;
+  get value {
+    if (_callback != null) return _value;
+    return _oneTime(_expr, _scope, _converter);
+  }
 
-  @reflectable set value(v) {
+  set value(v) {
     try {
       assign(_expr, v, _scope);
     } on EvalException catch (e) {
       _logger.warning("Error evaluating expression '$_expr': ${e.message}");
     }
   }
+
+  open(callback(value)) {
+    if (_callback != null) throw new StateError('already open');
+
+    _callback = callback;
+    final expr = observe(_expr, _scope);
+    _expr = expr;
+    _sub = expr.onUpdate.listen(_setValue)..onError((e) {
+      _logger.warning("Error evaluating expression '$_expr': ${e.message}");
+    });
+    try {
+      update(expr, _scope);
+      _value = _convertValue(expr.currentValue, _scope, _converter);
+    } on EvalException catch (e) {
+      _logger.warning("Error evaluating expression '$_expr': ${e.message}");
+    }
+    return _value;
+  }
+
+  void close() {
+    if (_callback == null) return;
+
+    _sub.cancel();
+    _sub = null;
+    _expr = (_expr as ExpressionObserver).expression;
+    _callback = null;
+  }
 }
diff --git a/pkg/polymer_expressions/test/bindings_test.dart b/pkg/polymer_expressions/test/bindings_test.dart
index 26a3a14..209012d 100644
--- a/pkg/polymer_expressions/test/bindings_test.dart
+++ b/pkg/polymer_expressions/test/bindings_test.dart
@@ -4,17 +4,18 @@
 
 library bindings_test;
 
+import 'dart:async';
 import 'dart:html';
 
 import 'package:logging/logging.dart';
 import 'package:observe/observe.dart';
-import 'package:observe/src/microtask.dart';
+import 'package:observe/src/dirty_check.dart' show dirtyCheckZone;
 import 'package:polymer_expressions/polymer_expressions.dart';
 import 'package:template_binding/template_binding.dart' show templateBind;
 import 'package:unittest/html_config.dart';
 import 'package:unittest/unittest.dart';
 
-main() {
+main() => dirtyCheckZone().run(() {
   useHtmlConfiguration();
 
   group('bindings', () {
@@ -34,89 +35,93 @@
       messages = [];
     });
 
-    observeTest('should update binding when data changes', () {
+    test('should update binding when data changes', () {
       var model = new NotifyModel();
       var binding = new PolymerExpressions()
-          .prepareBinding('x', null, null)(model, null);
+          .prepareBinding('x', null, null)(model, null, false);
       expect(binding.value, isNull);
       model.x = "hi";
-      performMicrotaskCheckpoint();
-      expect(binding.value, 'hi');
-      expect(messages.length, 0);
+      return new Future(() {
+        expect(binding.value, 'hi');
+        expect(messages.length, 0);
+      });
     });
 
-    observeTest('should update text content when data changes', () {
+    test('should update text content when data changes', () {
       var model = new NotifyModel('abcde');
       var template = templateBind(new Element.html(
           '<template><span>{{x}}</span></template>'));
       testDiv.append(template.createInstance(model, new PolymerExpressions()));
 
-      performMicrotaskCheckpoint();
-      var el = testDiv.query("span");
-      expect(el.text, 'abcde');
-      expect(model.x, 'abcde');
-      model.x = '___';
+      return new Future(() {
+        var el = testDiv.query("span");
+        expect(el.text, 'abcde');
+        expect(model.x, 'abcde');
+        model.x = '___';
 
-      performMicrotaskCheckpoint();
-      expect(model.x, '___');
-      expect(el.text, '___');
+        return new Future(() {
+          expect(model.x, '___');
+          expect(el.text, '___');
+        });
+      });
     });
 
-    observeTest('should log eval exceptions', () {
+    test('should log eval exceptions', () {
       var model = new NotifyModel('abcde');
       var template = templateBind(new Element.html(
           '<template><span>{{foo}}</span></template>'));
       testDiv.append(template.createInstance(model, new PolymerExpressions()));
-      performMicrotaskCheckpoint();
-      expect(messages.length, 1);
-      expect(messages[0].message,
-          "Error evaluating expression 'foo': variable 'foo' not found");
+
+      return new Future(() {
+        expect(messages.length, 1);
+        expect(messages[0].message,
+            "Error evaluating expression 'foo': variable 'foo' not found");
+      });
     });
 
-    observeTest('should preserve the cursor position', () {
+    test('should preserve the cursor position', () {
       var model = new NotifyModel('abcde');
       var template = templateBind(new Element.html(
           '<template><input id="i1" value={{x}}></template>'));
       testDiv.append(template.createInstance(model, new PolymerExpressions()));
 
-      performMicrotaskCheckpoint();
-      var el = testDiv.query("#i1");
-      var subscription = el.onInput.listen(expectAsync1((_) {
-        performMicrotaskCheckpoint();
-      }, count: 1));
-      el.focus();
+      return new Future(() {
+        var el = testDiv.query("#i1");
+        var subscription = el.onInput.listen(expectAsync1((_) {}, count: 1));
+        el.focus();
 
-      expect(el.value, 'abcde');
-      expect(model.x, 'abcde');
+        expect(el.value, 'abcde');
+        expect(model.x, 'abcde');
 
-      el.selectionStart = 3;
-      el.selectionEnd = 3;
-      expect(el.selectionStart, 3);
-      expect(el.selectionEnd, 3);
+        el.selectionStart = 3;
+        el.selectionEnd = 3;
+        expect(el.selectionStart, 3);
+        expect(el.selectionEnd, 3);
 
-      el.value = 'abc de';
-      // Updating the input value programatically (even to the same value in
-      // Chrome) loses the selection position.
-      expect(el.selectionStart, 6);
-      expect(el.selectionEnd, 6);
+        el.value = 'abc de';
+        // Updating the input value programatically (even to the same value in
+        // Chrome) loses the selection position.
+        expect(el.selectionStart, 6);
+        expect(el.selectionEnd, 6);
 
-      el.selectionStart = 4;
-      el.selectionEnd = 4;
+        el.selectionStart = 4;
+        el.selectionEnd = 4;
 
-      expect(model.x, 'abcde');
-      el.dispatchEvent(new Event('input'));
-      expect(model.x, 'abc de');
-      expect(el.value, 'abc de');
+        expect(model.x, 'abcde');
+        el.dispatchEvent(new Event('input'));
+        expect(model.x, 'abc de');
+        expect(el.value, 'abc de');
 
-      // But propagating observable values through reassign the value and
-      // selection will be preserved.
-      expect(el.selectionStart, 4);
-      expect(el.selectionEnd, 4);
+        // But propagating observable values through reassign the value and
+        // selection will be preserved.
+        expect(el.selectionStart, 4);
+        expect(el.selectionEnd, 4);
 
-      subscription.cancel();
+        subscription.cancel();
+      });
     });
   });
-}
+});
 
 @reflectable
 class NotifyModel extends ChangeNotifier {
@@ -128,5 +133,3 @@
     _x = notifyPropertyChange(#x, _x, value);
   }
 }
-
-observeTest(name, testCase) => test(name, wrapMicrotask(testCase));
diff --git a/pkg/polymer_expressions/test/globals_test.dart b/pkg/polymer_expressions/test/globals_test.dart
index 295aa11..9690baf 100644
--- a/pkg/polymer_expressions/test/globals_test.dart
+++ b/pkg/polymer_expressions/test/globals_test.dart
@@ -2,17 +2,17 @@
 // 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.
 
+import 'dart:async';
 import 'dart:html';
 
 import 'package:observe/observe.dart';
-import 'package:observe/src/microtask.dart';
 import 'package:polymer_expressions/polymer_expressions.dart';
 import 'package:template_binding/template_binding.dart';
 import 'package:unittest/unittest.dart';
-import 'package:unittest/html_enhanced_config.dart';
+import 'package:unittest/html_config.dart';
 
 main() {
-  useHtmlEnhancedConfiguration();
+  useHtmlConfiguration();
 
   var testDiv;
   group('enumerate', () {
@@ -34,23 +34,23 @@
       testDiv = null;
     });
 
-    test('should enumerate item and index', wrapMicrotask(() {
+    test('should enumerate item and index', () {
       templateBind(testDiv.query('template'))
           ..bindingDelegate = new PolymerExpressions()
           ..model = toObservable(
               ['hello', 'from', 'polymer', 'expressions']);
 
-      performMicrotaskCheckpoint();
+      return new Future(() {
+        expect(testDiv.queryAll('div').map((n) => n.text), [
+          'Item 0 is hello',
+          'Item 1 is from',
+          'Item 2 is polymer',
+          'Item 3 is expressions',
+        ]);
+      });
+    });
 
-      expect(testDiv.queryAll('div').map((n) => n.text), [
-        'Item 0 is hello',
-        'Item 1 is from',
-        'Item 2 is polymer',
-        'Item 3 is expressions',
-      ]);
-    }));
-
-    test('should update after changes', wrapMicrotask(() {
+    test('should update after changes', () {
       var model = toObservable(
               ['hello', 'from', 'polymer', 'expressions', 'a', 'b', 'c']);
 
@@ -58,34 +58,34 @@
           ..bindingDelegate = new PolymerExpressions()
           ..model = model;
 
-      performMicrotaskCheckpoint();
+      return new Future(() {
+        expect(testDiv.queryAll('div').map((n) => n.text), [
+          'Item 0 is hello',
+          'Item 1 is from',
+          'Item 2 is polymer',
+          'Item 3 is expressions',
+          'Item 4 is a',
+          'Item 5 is b',
+          'Item 6 is c',
+        ]);
 
-      expect(testDiv.queryAll('div').map((n) => n.text), [
-        'Item 0 is hello',
-        'Item 1 is from',
-        'Item 2 is polymer',
-        'Item 3 is expressions',
-        'Item 4 is a',
-        'Item 5 is b',
-        'Item 6 is c',
-      ]);
+        model.removeAt(1);
+        model[1] = 'world';
+        model[2] = '!';
+        model.insert(5, 'e');
 
-      model.removeAt(1);
-      model[1] = 'world';
-      model[2] = '!';
-      model.insert(5, 'e');
-
-      performMicrotaskCheckpoint();
-
-      expect(testDiv.queryAll('div').map((n) => n.text), [
-        'Item 0 is hello',
-        'Item 1 is world',
-        'Item 2 is !',
-        'Item 3 is a',
-        'Item 4 is b',
-        'Item 5 is e',
-        'Item 6 is c',
-      ]);
-    }));
+        return new Future(() {
+          expect(testDiv.queryAll('div').map((n) => n.text), [
+            'Item 0 is hello',
+            'Item 1 is world',
+            'Item 2 is !',
+            'Item 3 is a',
+            'Item 4 is b',
+            'Item 5 is e',
+            'Item 6 is c',
+          ]);
+        });
+      });
+    });
   });
 }
diff --git a/pkg/polymer_expressions/test/syntax_test.dart b/pkg/polymer_expressions/test/syntax_test.dart
index b5dc01f..50972e3 100644
--- a/pkg/polymer_expressions/test/syntax_test.dart
+++ b/pkg/polymer_expressions/test/syntax_test.dart
@@ -9,11 +9,11 @@
 import 'package:observe/observe.dart';
 import 'package:polymer_expressions/polymer_expressions.dart';
 import 'package:template_binding/template_binding.dart';
-import 'package:unittest/html_enhanced_config.dart';
+import 'package:unittest/html_config.dart';
 import 'package:unittest/unittest.dart';
 
 main() {
-  useHtmlEnhancedConfiguration();
+  useHtmlConfiguration();
 
   group('PolymerExpressions', () {
     var testDiv;
@@ -67,7 +67,9 @@
       var logFuture = logger.onRecord.toList();
       testDiv.nodes.add(new Element.html('''
           <template id="test" bind>{{ foo }}</template>'''));
-      templateBind(query('#test')).bindingDelegate = new PolymerExpressions();
+      templateBind(query('#test'))
+          ..bindingDelegate = new PolymerExpressions()
+          ..model = [];
       return new Future(() {
         logger.clearListeners();
         return logFuture.then((records) {
diff --git a/pkg/scheduled_test/lib/scheduled_test.dart b/pkg/scheduled_test/lib/scheduled_test.dart
index bf47adb..6713054 100644
--- a/pkg/scheduled_test/lib/scheduled_test.dart
+++ b/pkg/scheduled_test/lib/scheduled_test.dart
@@ -238,17 +238,16 @@
       return currentSchedule.run(() {
         if (_setUpFn != null) _setUpFn();
         body();
+      }).catchError((error, stackTrace) {
+        if (error is ScheduleError) {
+          assert(error.schedule.errors.contains(error));
+          assert(error.schedule == currentSchedule);
+          unittest.registerException(error.schedule.errorString());
+        } else {
+          unittest.registerException(error, new Chain.forTrace(stackTrace));
+        }
       }).then(completer.complete);
-    }, onError: (e, chain) {
-      if (e is ScheduleError) {
-        assert(e.schedule.errors.contains(e));
-        assert(e.schedule == currentSchedule);
-        unittest.registerException(e.schedule.errorString());
-      } else {
-        unittest.registerException(e, chain);
-      }
-      completer.complete();
-    });
+    }, onError: (error, chain) => currentSchedule.signalError(error, chain));
 
     return completer.future;
   });
diff --git a/pkg/scheduled_test/test/scheduled_test/unhandled_error_test.dart b/pkg/scheduled_test/test/scheduled_test/unhandled_error_test.dart
new file mode 100644
index 0000000..aaf87f3
--- /dev/null
+++ b/pkg/scheduled_test/test/scheduled_test/unhandled_error_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2014, 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.
+
+import 'dart:async';
+
+import 'package:scheduled_test/scheduled_test.dart';
+import 'package:scheduled_test/src/mock_clock.dart' as mock_clock;
+
+import '../metatest.dart';
+import '../utils.dart';
+
+void main(_, message) {
+  initMetatest(message);
+
+  setUpTimeout();
+
+  expectTestFails("a top-leveled error should be converted to a schedule error",
+      () {
+    schedule(() {
+      new Future.microtask(() => throw 'error');
+      return pumpEventQueue();
+    });
+  }, (errors) {
+    expect(errors.first.error, equals('error'));
+  });
+}
diff --git a/pkg/shadow_dom/pubspec.yaml b/pkg/shadow_dom/pubspec.yaml
index 0c3bb3e..fc1a529 100644
--- a/pkg/shadow_dom/pubspec.yaml
+++ b/pkg/shadow_dom/pubspec.yaml
@@ -1,5 +1,5 @@
 name: shadow_dom
-version: 0.9.1
+version: 0.9.2
 author: Polymer.dart Authors <web-ui-dev@dartlang.org>
 homepage: https://www.dartlang.org/polymer-dart/
 description: >
@@ -9,4 +9,4 @@
   within a document, thus enabling better functional encapsulation within the
   DOM.
 environment:
-  sdk: ">=1.0.0 <2.0.0"
+  sdk: ">=1.2.0-dev.3.0 <2.0.0"
diff --git a/pkg/template_binding/lib/src/binding_delegate.dart b/pkg/template_binding/lib/src/binding_delegate.dart
index 0a9cb51..4d9f8d2 100644
--- a/pkg/template_binding/lib/src/binding_delegate.dart
+++ b/pkg/template_binding/lib/src/binding_delegate.dart
@@ -66,7 +66,7 @@
       Element template) => null;
 }
 
-typedef PrepareBindingFunction(model, Node node);
+typedef PrepareBindingFunction(model, Node node, bool oneTime);
 
 typedef PrepareInstanceModelFunction(model);
 
diff --git a/pkg/template_binding/lib/src/element.dart b/pkg/template_binding/lib/src/element.dart
index 1ee43f9..bf9a036 100644
--- a/pkg/template_binding/lib/src/element.dart
+++ b/pkg/template_binding/lib/src/element.dart
@@ -8,76 +8,63 @@
 class _ElementExtension extends NodeBindExtension {
   _ElementExtension(Element node) : super._(node);
 
-  NodeBinding bind(String name, model, [String path]) {
+  bind(String name, value, {bool oneTime: false}) {
     _self.unbind(name);
 
-    var binding;
-    if (_node is OptionElement && name == 'value') {
+    Element node = _node;
+
+    if (node is OptionElement && name == 'value') {
       // Note: because <option> can be a semantic template, <option> will be
       // a TemplateBindExtension sometimes. So we need to handle it here.
-      (_node as OptionElement).attributes.remove(name);
-      binding = new _OptionValueBinding(_node, model, path);
-    } else {
-      binding = new _AttributeBinding(_node, name, model, path);
-    }
-    return bindings[name] = binding;
-  }
-}
-
-class _AttributeBinding extends NodeBinding {
-  final bool conditional;
-
-  _AttributeBinding._(node, name, model, path, this.conditional)
-      : super(node, name, model, path);
-
-  factory _AttributeBinding(Element node, name, model, path) {
-    bool conditional = name.endsWith('?');
-    if (conditional) {
       node.attributes.remove(name);
-      name = name.substring(0, name.length - 1);
-    }
-    return new _AttributeBinding._(node, name, model, path, conditional);
-  }
 
-  Element get node => super.node;
-
-  void valueChanged(value) {
-    if (conditional) {
-      if (_toBoolean(value)) {
-        node.attributes[property] = '';
-      } else {
-        node.attributes.remove(property);
-      }
+      if (oneTime) return _updateOption(value);
+      _open(value, _updateOption);
     } else {
-      // TODO(jmesserly): escape value if needed to protect against XSS.
-      // See https://github.com/polymer-project/mdv/issues/58
-      node.attributes[property] = sanitizeBoundValue(value);
+      bool conditional = name.endsWith('?');
+      if (conditional) {
+        node.attributes.remove(name);
+        name = name.substring(0, name.length - 1);
+      }
+
+      if (oneTime) return _updateAttribute(_node, name, conditional, value);
+
+      _open(value, (x) => _updateAttribute(_node, name, conditional, x));
     }
+    return bindings[name] = value;
   }
-}
 
-class _OptionValueBinding extends _ValueBinding {
-  _OptionValueBinding(node, model, path) : super(node, model, path);
-
-  OptionElement get node => super.node;
-
-  void valueChanged(newValue) {
+  void _updateOption(newValue) {
+    OptionElement node = _node;
     var oldValue = null;
     var selectBinding = null;
-    var select = node.parent;
+    var select = node.parentNode;
     if (select is SelectElement) {
       var valueBinding = nodeBind(select).bindings['value'];
-      if (valueBinding is _SelectBinding) {
+      if (valueBinding is _InputBinding) {
         selectBinding = valueBinding;
         oldValue = select.value;
       }
     }
 
-    super.valueChanged(newValue);
+    node.value = _sanitizeValue(newValue);
 
-    if (selectBinding != null && !selectBinding.closed &&
-        select.value != oldValue) {
-      selectBinding.nodeValueChanged(null);
+    if (selectBinding != null && select.value != oldValue) {
+      selectBinding.value = select.value;
     }
   }
 }
+
+void _updateAttribute(Element node, String name, bool conditional, value) {
+  if (conditional) {
+    if (_toBoolean(value)) {
+      node.attributes[name] = '';
+    } else {
+      node.attributes.remove(name);
+    }
+  } else {
+    // TODO(jmesserly): escape value if needed to protect against XSS.
+    // See https://github.com/polymer-project/mdv/issues/58
+    node.attributes[name] = _sanitizeValue(value);
+  }
+}
diff --git a/pkg/template_binding/lib/src/input_bindings.dart b/pkg/template_binding/lib/src/input_bindings.dart
index 06b744f..6292527 100644
--- a/pkg/template_binding/lib/src/input_bindings.dart
+++ b/pkg/template_binding/lib/src/input_bindings.dart
@@ -4,21 +4,79 @@
 
 part of template_binding;
 
-abstract class _InputBinding extends NodeBinding {
-  StreamSubscription _eventSub;
 
-  _InputBinding(node, name, model, path): super(node, name, model, path) {
-    _eventSub = _getStreamForInputType(node).listen(nodeValueChanged);
+// Note: the JavaScript version monkeypatches(!!) the close method of the passed
+// in Bindable. We use a wrapper instead.
+class _InputBinding extends Bindable {
+  // Note: node can be an InputElement or TextAreaElement. Both have "value".
+  var _node;
+  StreamSubscription _eventSub;
+  Bindable _bindable;
+  String _propertyName;
+
+  _InputBinding(this._node, this._bindable, this._propertyName) {
+    _eventSub = _getStreamForInputType(_node).listen(_nodeChanged);
+    _updateNode(open(_updateNode));
   }
 
-  void valueChanged(newValue);
+  void _updateNode(newValue) => _updateProperty(_node, newValue, _propertyName);
 
-  void nodeValueChanged(e);
+  static void _updateProperty(node, newValue, String propertyName) {
+    switch (propertyName) {
+      case 'checked':
+        node.checked = _toBoolean(newValue);
+        return;
+      case 'selectedIndex':
+        node.selectedIndex = _toInt(newValue);
+        return;
+      case 'value':
+        node.value = _sanitizeValue(newValue);
+        return;
+    }
+  }
+
+  void _nodeChanged(e) {
+    switch (_propertyName) {
+      case 'value':
+        value = _node.value;
+        break;
+      case 'checked':
+        value = _node.checked;
+
+        // Only the radio button that is getting checked gets an event. We
+        // therefore find all the associated radio buttons and update their
+        // checked binding manually.
+        if (_node is InputElement && _node.type == 'radio') {
+          for (var r in _getAssociatedRadioButtons(_node)) {
+            var checkedBinding = nodeBind(r).bindings['checked'];
+            if (checkedBinding != null) {
+              // Set the value directly to avoid an infinite call stack.
+              checkedBinding.value = false;
+            }
+          }
+        }
+        break;
+      case 'selectedIndex':
+        value = _node.selectedIndex;
+        break;
+    }
+
+    Observable.dirtyCheck();
+  }
+
+  open(callback(value)) => _bindable.open(callback);
+  get value => _bindable.value;
+  set value(newValue) => _bindable.value = newValue;
 
   void close() {
-    if (closed) return;
-    _eventSub.cancel();
-    super.close();
+    if (_eventSub != null) {
+      _eventSub.cancel();
+      _eventSub = null;
+    }
+    if (_bindable != null) {
+      _bindable.close();
+      _bindable = null;
+    }
   }
 
   static EventStreamProvider<Event> _checkboxEventType = () {
@@ -53,51 +111,6 @@
         return element.onInput;
     }
   }
-}
-
-class _ValueBinding extends _InputBinding {
-  _ValueBinding(node, model, path) : super(node, 'value', model, path);
-
-  get node => super.node;
-
-  void valueChanged(newValue) {
-    // Note: node can be an InputElement or TextAreaElement. Both have "value".
-    node.value = sanitizeBoundValue(newValue);
-  }
-
-  void nodeValueChanged(e) {
-    value = node.value;
-    Observable.dirtyCheck();
-  }
-}
-
-class _CheckedBinding extends _InputBinding {
-  _CheckedBinding(node, model, path) : super(node, 'checked', model, path);
-
-  InputElement get node => super.node;
-
-  void valueChanged(newValue) {
-    node.checked = _toBoolean(newValue);
-  }
-
-  void nodeValueChanged(e) {
-    value = node.checked;
-
-    // Only the radio button that is getting checked gets an event. We
-    // therefore find all the associated radio buttons and update their
-    // CheckedBinding manually.
-    if (node is InputElement && node.type == 'radio') {
-      for (var r in _getAssociatedRadioButtons(node)) {
-        var checkedBinding = nodeBind(r).bindings['checked'];
-        if (checkedBinding != null) {
-          // Set the value directly to avoid an infinite call stack.
-          checkedBinding.value = false;
-        }
-      }
-    }
-
-    Observable.dirtyCheck();
-  }
 
   // |element| is assumed to be an HTMLInputElement with |type| == 'radio'.
   // Returns an array containing all radio buttons other than |element| that
@@ -125,63 +138,6 @@
       return radios.where((el) => el != element && el.form == null);
     }
   }
-}
-
-class _SelectBinding extends _InputBinding {
-  MutationObserver _onMutation;
-
-  _SelectBinding(node, property, model, path)
-      : super(node, property, model, path);
-
-  SelectElement get node => super.node;
-
-  void valueChanged(newValue) {
-    _cancelMutationObserver();
-
-    if (_tryUpdateValue(newValue)) return;
-
-    // It could be that a template will expand an <option> child (or grandchild,
-    // if we have an <optgroup> in between). Since selected index cannot be set
-    // if the children aren't created yet, we need to wait for them to be
-    // created do this with a MutationObserver.
-    // Dart note: unlike JS we use mutation observers to avoid:
-    // https://github.com/Polymer/NodeBind/issues/5
-
-    // Note: it doesn't matter when the children get added; even if they get
-    // added much later, presumably we want the selected index data binding to
-    // still take effect.
-    _onMutation = new MutationObserver((x, y) {
-      if (_tryUpdateValue(value)) _cancelMutationObserver();
-    })..observe(node, childList: true, subtree: true);
-  }
-
-  bool _tryUpdateValue(newValue) {
-    if (property == 'selectedIndex') {
-      var intValue = _toInt(newValue);
-      node.selectedIndex = intValue;
-      return node.selectedIndex == intValue;
-    } else if (property == 'value') {
-      node.value = sanitizeBoundValue(newValue);
-      return node.value == newValue;
-    }
-  }
-
-  void _cancelMutationObserver() {
-    if (_onMutation != null) {
-      _onMutation.disconnect();
-      _onMutation = null;
-    }
-  }
-
-  void nodeValueChanged(e) {
-    _cancelMutationObserver();
-
-    if (property == 'selectedIndex') {
-      value = node.selectedIndex;
-    } else if (property == 'value') {
-      value = node.value;
-    }
-  }
 
   // TODO(jmesserly,sigmund): I wonder how many bindings typically convert from
   // one type to another (e.g. value-as-number) and whether it is useful to
diff --git a/pkg/template_binding/lib/src/input_element.dart b/pkg/template_binding/lib/src/input_element.dart
index a599f24..e399435 100644
--- a/pkg/template_binding/lib/src/input_element.dart
+++ b/pkg/template_binding/lib/src/input_element.dart
@@ -10,15 +10,18 @@
 
   InputElement get _node => super._node;
 
-  NodeBinding bind(String name, model, [String path]) {
+  Bindable bind(String name, value, {bool oneTime: false}) {
     if (name != 'value' && name != 'checked') {
-      return super.bind(name, model, path);
+      return super.bind(name, value, oneTime: oneTime);
+    }
+
+    _node.attributes.remove(name);
+    if (oneTime) {
+      _InputBinding._updateProperty(_node, value, name);
+      return null;
     }
 
     _self.unbind(name);
-    _node.attributes.remove(name);
-    return bindings[name] = name == 'value' ?
-        new _ValueBinding(_node, model, path) :
-        new _CheckedBinding(_node, model, path);
+    return bindings[name] = new _InputBinding(_node, value, name);
   }
 }
diff --git a/pkg/template_binding/lib/src/instance_binding_map.dart b/pkg/template_binding/lib/src/instance_binding_map.dart
index 71b0c12..ad34b6e 100644
--- a/pkg/template_binding/lib/src/instance_binding_map.dart
+++ b/pkg/template_binding/lib/src/instance_binding_map.dart
@@ -6,66 +6,68 @@
 
 class _InstanceBindingMap {
   final List bindings;
-  final Map<int, _InstanceBindingMap> children;
-  final Node templateRef;
+  List<_InstanceBindingMap> children;
+  DocumentFragment content;
 
-  // Workaround for:
-  // https://github.com/Polymer/TemplateBinding/issues/150
-  final int numChildren;
+  bool get isTemplate => false;
 
-  _InstanceBindingMap._(this.bindings, this.children, this.templateRef,
-      this.numChildren);
+  _InstanceBindingMap(this.bindings);
+
+  _InstanceBindingMap getChild(int index) {
+    if (children == null || index >= children.length) return null;
+    return children[index];
+  }
+}
+
+class _TemplateBindingMap extends _InstanceBindingMap {
+  bool get isTemplate => true;
+
+  MustacheTokens _if, _bind, _repeat;
+
+  _TemplateBindingMap(List bindings) : super(bindings);
 }
 
 _InstanceBindingMap _createInstanceBindingMap(Node node,
     BindingDelegate delegate) {
 
-  var bindings = _getBindings(node, delegate);
-  Node templateRef = null;
+  _InstanceBindingMap map = _getBindings(node, delegate);
+  if (map == null) map = new _InstanceBindingMap([]);
 
-  if (isSemanticTemplate(node)) templateRef = node;
-
-  Map children = null;
-  int i = 0;
-  for (var c = node.firstChild; c != null; c = c.nextNode, i++) {
+  List children = null;
+  int index = 0;
+  for (var c = node.firstChild; c != null; c = c.nextNode, index++) {
     var childMap = _createInstanceBindingMap(c, delegate);
     if (childMap == null) continue;
 
-    if (children == null) children = new HashMap();
-    children[i] = childMap;
+    // TODO(jmesserly): use a sparse map instead?
+    if (children == null) children = new List(node.nodes.length);
+    children[index] = childMap;
   }
+  map.children = children;
 
-  if (bindings == null && children == null && templateRef == null) return null;
-
-  return new _InstanceBindingMap._(bindings, children, templateRef, i);
+  return map;
 }
 
-void _addMapBindings(Node node, _InstanceBindingMap map, model,
-    BindingDelegate delegate, List bound) {
-  if (map == null) return;
+Node _cloneAndBindInstance(Node node, Node parent, Document stagingDocument,
+    _InstanceBindingMap bindings, model, BindingDelegate delegate,
+    List instanceBindings, [TemplateInstance instanceRecord]) {
 
-  if (map.templateRef != null) {
-    TemplateBindExtension.decorate(node, map.templateRef);
+  var clone = parent.append(stagingDocument.importNode(node, false));
+
+  int i = 0;
+  for (var c = node.firstChild; c != null; c = c.nextNode, i++) {
+    var childMap = bindings != null ? bindings.getChild(i) : null;
+    _cloneAndBindInstance(c, clone, stagingDocument, childMap, model, delegate,
+        instanceBindings);
+  }
+
+  if (bindings.isTemplate) {
+    TemplateBindExtension.decorate(clone, node);
     if (delegate != null) {
-      templateBindFallback(node)._bindingDelegate = delegate;
+      templateBindFallback(clone).bindingDelegate = delegate;
     }
   }
 
-  if (map.bindings != null) {
-    _processBindings(map.bindings, node, model, bound);
-  }
-
-  if (map.children == null) return;
-
-  // To workaround https://github.com/Polymer/TemplateBinding/issues/150,
-  // we try and detect cases where creating a custom element resulted in extra
-  // children compared to what we expected. We assume these new children are all
-  // at the beginning, because _deepCloneIgnoreTemplateContent creates the
-  // element then appends the template content's children to the end.
-
-  int i = map.numChildren - node.nodes.length;
-  for (var c = node.firstChild; c != null; c = c.nextNode, i++) {
-    if (i < 0) continue;
-    _addMapBindings(c, map.children[i], model, delegate, bound);
-  }
+  _processBindings(clone, bindings, model, instanceBindings);
+  return clone;
 }
diff --git a/pkg/template_binding/lib/src/mustache_tokens.dart b/pkg/template_binding/lib/src/mustache_tokens.dart
new file mode 100644
index 0000000..be84d26
--- /dev/null
+++ b/pkg/template_binding/lib/src/mustache_tokens.dart
@@ -0,0 +1,146 @@
+// 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.
+
+library template_binding.src.mustache_tokens;
+
+import 'package:observe/observe.dart';
+import 'package:template_binding/template_binding.dart';
+
+/**
+ * Represents a set of parsed tokens from a {{ mustache binding expression }}.
+ * This can be created by calling [parse].
+ *
+ * For performance reasons the data is stored in one linear array in [_tokens].
+ * This class wraps that array and provides accessors in an attempt to make the
+ * pattern easier to understand. See [length] and [getText] for example.
+ */
+class MustacheTokens {
+  // Constants for indexing into the exploded structs in [_tokens] .
+  static const _TOKEN_TEXT = 0;
+  static const _TOKEN_ONETIME = 1;
+  static const _TOKEN_PATH = 2;
+  static const _TOKEN_PREPAREFN = 3;
+  static const _TOKEN_SIZE = 4;
+
+  // There is 1 extra entry for the end text.
+  static const _TOKEN_ENDTEXT = 1;
+
+  bool get hasOnePath => _tokens.length == _TOKEN_SIZE + _TOKEN_ENDTEXT;
+  bool get isSimplePath => hasOnePath &&
+      _tokens[_TOKEN_TEXT] == '' && _tokens[_TOKEN_SIZE + _TOKEN_TEXT] == '';
+
+  /**
+   * [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+] if there is at least one
+   * mustache.
+   */
+  final List _tokens;
+
+  final bool onlyOneTime;
+
+  // Dart note: I think this is cached in JavaScript to avoid an extra
+  // allocation per template instance. Seems reasonable, so we do the same.
+  Function _combinator;
+  Function get combinator => _combinator;
+
+  MustacheTokens._(this._tokens, this.onlyOneTime) {
+    // Should be: [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+].
+    assert((_tokens.length - _TOKEN_ENDTEXT) % _TOKEN_SIZE == 0);
+
+    _combinator = hasOnePath ? _singleCombinator : _listCombinator;
+  }
+
+  int get length => _tokens.length ~/ _TOKEN_SIZE;
+
+  /**
+   * Gets the [i]th text entry. Note that [length] can be passed to get the
+   * final text entry.
+   */
+  String getText(int i) => _tokens[i * _TOKEN_SIZE + _TOKEN_TEXT];
+
+  /** Gets the oneTime flag for the [i]th token. */
+  bool getOneTime(int i) => _tokens[i * _TOKEN_SIZE + _TOKEN_ONETIME];
+
+  /** Gets the path for the [i]th token. */
+  PropertyPath getPath(int i) => _tokens[i * _TOKEN_SIZE + _TOKEN_PATH];
+
+  /** Gets the prepareBinding function for the [i]th token. */
+  Function getPrepareBinding(int i) =>
+      _tokens[i * _TOKEN_SIZE + _TOKEN_PREPAREFN];
+
+
+  /**
+   * Parses {{ mustache }} bindings.
+   *
+   * Returns null if there are no matches. Otherwise returns the parsed tokens.
+   */
+  static MustacheTokens parse(String s, String name, node,
+      BindingDelegate delegate) {
+    if (s == null || s.isEmpty) return null;
+
+    var tokens = null;
+    var length = s.length;
+    var lastIndex = 0;
+    var onlyOneTime = true;
+    while (lastIndex < length) {
+      var startIndex = s.indexOf('{{', lastIndex);
+      var oneTimeStart = s.indexOf('[[', lastIndex);
+      var oneTime = false;
+      var terminator = '}}';
+
+      if (oneTimeStart >= 0 &&
+          (startIndex < 0 || oneTimeStart < startIndex)) {
+        startIndex = oneTimeStart;
+        oneTime = true;
+        terminator = ']]';
+      }
+
+      var endIndex = -1;
+      if (startIndex >= 0) {
+        endIndex = s.indexOf(terminator, startIndex + 2);
+      }
+
+      if (endIndex < 0) {
+        if (tokens == null) return null;
+
+        tokens.add(s.substring(lastIndex)); // TEXT
+        break;
+      }
+
+      if (tokens == null) tokens = [];
+      tokens.add(s.substring(lastIndex, startIndex)); // TEXT
+      var pathString = s.substring(startIndex + 2, endIndex).trim();
+      tokens.add(oneTime); // ONETIME?
+      onlyOneTime = onlyOneTime && oneTime;
+      tokens.add(new PropertyPath(pathString)); // PATH
+      var delegateFn = delegate == null ? null :
+          delegate.prepareBinding(pathString, name, node);
+      tokens.add(delegateFn);
+
+      lastIndex = endIndex + 2;
+    }
+
+    if (lastIndex == length) tokens.add('');
+
+    return new MustacheTokens._(tokens, onlyOneTime);
+  }
+
+
+  // Dart note: split "combinator" into the single/list variants, so the
+  // argument can be typed.
+  String _singleCombinator(Object value) {
+    if (value == null) value = '';
+    return '${getText(0)}$value${getText(length)}';
+  }
+
+  String _listCombinator(List<Object> values) {
+    var newValue = new StringBuffer(getText(0));
+    int len = this.length;
+    for (var i = 0; i < len; i++) {
+      var value = values[i];
+      if (value != null) newValue.write(value);
+      newValue.write(getText(i + 1));
+    }
+    return newValue.toString();
+  }
+}
diff --git a/pkg/template_binding/lib/src/node.dart b/pkg/template_binding/lib/src/node.dart
index a5fb835..595cbeb 100644
--- a/pkg/template_binding/lib/src/node.dart
+++ b/pkg/template_binding/lib/src/node.dart
@@ -7,18 +7,21 @@
 /** Extensions to the [Node] API. */
 class NodeBindExtension {
   final Node _node;
-  Map<String, NodeBinding> _bindings;
+  Map<String, Bindable> _bindings;
 
   NodeBindExtension._(this._node);
 
   /**
    * Binds the attribute [name] to the [path] of the [model].
    * Path is a String of accessors such as `foo.bar.baz`.
-   * Returns the `NodeBinding` instance.
+   * Returns the `Bindable` instance.
    */
-  NodeBinding bind(String name, model, [String path]) {
+  Bindable bind(String name, value, {bool oneTime: false}) {
+    // TODO(jmesserly): in Dart we could deliver an async error, which would
+    // have a similar affect but be reported as a test failure. Should we?
     window.console.error('Unhandled binding to Node: '
-        '$this $name $model $path');
+        '$this $name $value $oneTime');
+    return null;
   }
 
   /** Unbinds the attribute [name]. */
@@ -39,8 +42,8 @@
 
   // TODO(jmesserly): we should return a read-only wrapper here.
   /** Gets the data bindings that are associated with this node. */
-  Map<String, NodeBinding> get bindings {
-    if (_bindings == null) _bindings = new LinkedHashMap<String, NodeBinding>();
+  Map<String, Bindable> get bindings {
+    if (_bindings == null) _bindings = new LinkedHashMap<String, Bindable>();
     return _bindings;
   }
 
@@ -57,6 +60,9 @@
   TemplateInstance get templateInstance =>
       _templateInstance != null ? _templateInstance :
       (_node.parent != null ? nodeBind(_node.parent).templateInstance : null);
+
+  _open(Bindable bindable, callback(value)) =>
+      callback(bindable.open(callback));
 }
 
 
@@ -66,17 +72,19 @@
   // in cases where script has modified the template instance boundary.
 
   /** The first node of this template instantiation. */
-  final Node firstNode;
+  Node get firstNode => _firstNode;
 
   /**
    * The last node of this template instantiation.
    * This could be identical to [firstNode] if the template only expanded to a
    * single node.
    */
-  final Node lastNode;
+  Node get lastNode => _lastNode;
 
   /** The model used to instantiate the template. */
   final model;
 
-  TemplateInstance(this.firstNode, this.lastNode, this.model);
+  Node _firstNode, _lastNode;
+
+  TemplateInstance(this.model);
 }
diff --git a/pkg/template_binding/lib/src/node_binding.dart b/pkg/template_binding/lib/src/node_binding.dart
deleted file mode 100644
index 95c5e00..0000000
--- a/pkg/template_binding/lib/src/node_binding.dart
+++ /dev/null
@@ -1,92 +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.
-
-library template_binding.src.node_binding;
-
-import 'dart:async' show StreamSubscription;
-import 'dart:html' show Node;
-import 'package:observe/observe.dart' show PathObserver, CompoundPathObserver;
-
-/** Test only method. Not re-exported. */
-getObserverForTest(NodeBinding binding) => binding._observer;
-
-/**
- * A data binding on a [Node].
- * See [NodeBindExtension.bindings] and [NodeBindExtension.bind].
- */
-abstract class NodeBinding {
-  Node _node;
-  var _model;
-
-  // TODO(jmesserly): need common interface for PathObserver,
-  // CompoundPathObserver.
-  var _observer;
-  StreamSubscription _pathSub;
-
-  /** The property of [node] which will be data bound. */
-  final String property;
-
-  /** The property of [node] which will be data bound. */
-  final String path;
-
-  /** The node that has [property] which will be data bound. */
-  Node get node => _node;
-
-  /** The bound data model. */
-  get model => _model;
-
-  /** True if this binding has been [closed]. */
-  bool get closed => _node == null;
-
-  /** The value at the [path] on [model]. */
-  get value => _observer.value;
-
-  set value(newValue) {
-    _observer.value = newValue;
-  }
-
-  NodeBinding(this._node, this.property, this._model, [String path])
-      : path = path != null ? path : '' {
-
-    // Fast path if we're observing "value"
-    if ((model is PathObserver || model is CompoundPathObserver) &&
-        path == 'value') {
-
-      _observer = model;
-    } else {
-      // Create the path observer
-      _observer = new PathObserver(model, this.path);
-    }
-
-    _pathSub = _observer.changes.listen((r) => valueChanged(value));
-    valueChanged(value);
-  }
-
-  /** Called when [value] changes to update the [node]. */
-  // TODO(jmesserly): the impl in template_binding uses reflection to set the
-  // property, but that isn't used except for specific known fields like
-  // "textContent", so I'm overridding this in the subclasses instead.
-  void valueChanged(newValue);
-
-  /** Called to sanitize the value before it is assigned into the property. */
-  sanitizeBoundValue(value) => value == null ? '' : '$value';
-
-  /**
-   * Called by [NodeBindExtension.unbind] to close this binding and unobserve
-   * the [path].
-   *
-   * This can be overridden in subclasses, but they must call `super.close()`
-   * to free associated resources. They must also check [closed] and return
-   * immediately if already closed.
-   */
-  void close() {
-    if (closed) return;
-
-    if (_pathSub != null) _pathSub.cancel();
-    _pathSub = null;
-    _observer = null;
-    _node = null;
-    _model = null;
-  }
-}
diff --git a/pkg/template_binding/lib/src/select_element.dart b/pkg/template_binding/lib/src/select_element.dart
index 432b049..f205a15 100644
--- a/pkg/template_binding/lib/src/select_element.dart
+++ b/pkg/template_binding/lib/src/select_element.dart
@@ -10,14 +10,21 @@
 
   SelectElement get _node => super._node;
 
-  NodeBinding bind(String name, model, [String path]) {
+  Bindable bind(String name, value, {bool oneTime: false}) {
     if (name == 'selectedindex') name = 'selectedIndex';
     if (name != 'selectedIndex' && name != 'value') {
-      return super.bind(name, model, path);
+      return super.bind(name, value, oneTime: oneTime);
+    }
+
+    // TODO(jmesserly): merge logic here with InputElement, it's the same except
+    // for the addition of selectedIndex as a valid property name.
+    _node.attributes.remove(name);
+    if (oneTime) {
+      _InputBinding._updateProperty(_node, value, name);
+      return null;
     }
 
     _self.unbind(name);
-    _node.attributes.remove(name);
-    return bindings[name] = new _SelectBinding(_node, name, model, path);
+    return bindings[name] = new _InputBinding(_node, value, name);
   }
 }
diff --git a/pkg/template_binding/lib/src/template.dart b/pkg/template_binding/lib/src/template.dart
index 8df84d1..d085a89 100644
--- a/pkg/template_binding/lib/src/template.dart
+++ b/pkg/template_binding/lib/src/template.dart
@@ -9,7 +9,7 @@
   var _model;
   BindingDelegate _bindingDelegate;
   _TemplateIterator _iterator;
-  bool _scheduled = false;
+  bool _setModelScheduled = false;
 
   Element _templateInstanceRef;
 
@@ -19,7 +19,7 @@
 
   HtmlDocument _stagingDocument;
 
-  var _bindingMap;
+  _InstanceBindingMap _bindingMap;
 
   TemplateBindExtension._(Element node) : super(node);
 
@@ -28,106 +28,70 @@
   TemplateBindExtension get _self => super._node is TemplateBindExtension
       ? _node : this;
 
-  NodeBinding bind(String name, model, [String path]) {
-    path = path != null ? path : '';
+  _TemplateIterator _processBindingDirectives(_TemplateBindingMap directives) {
+    if (_iterator != null) _iterator._closeDependencies();
+
+    if (directives._if == null &&
+        directives._bind == null &&
+        directives._repeat == null) {
+
+      if (_iterator != null) {
+        _iterator.close();
+        _iterator = null;
+        bindings.remove('iterator');
+      }
+      return null;
+    }
 
     if (_iterator == null) {
-      // TODO(jmesserly): since there's only one iterator, we could just
-      // inline it into this object.
-      _iterator = new _TemplateIterator(this);
+      bindings['iterator'] = _iterator = new _TemplateIterator(this);
     }
 
-    // Dart note: we return _TemplateBinding instead of _iterator.
-    // See comment on _TemplateBinding class.
-    switch (name) {
-      case 'bind':
-        _iterator..hasBind = true
-            ..bindModel = model
-            ..bindPath = path;
-        _scheduleIterator();
-        return bindings[name] = new _TemplateBinding(this, name, model, path);
-      case 'repeat':
-        _iterator..hasRepeat = true
-            ..repeatModel = model
-            ..repeatPath = path;
-        _scheduleIterator();
-        return bindings[name] = new _TemplateBinding(this, name, model, path);
-      case 'if':
-        _iterator..hasIf = true
-            ..ifModel = model
-            ..ifPath = path;
-        _scheduleIterator();
-        return bindings[name] = new _TemplateBinding(this, name, model, path);
-      default:
-        return super.bind(name, model, path);
-    }
-  }
-
-  void unbind(String name) {
-    switch (name) {
-      case 'bind':
-        if (_iterator == null) return;
-        _iterator..hasBind = false
-            ..bindModel = null
-            ..bindPath = null;
-        _scheduleIterator();
-        bindings.remove(name);
-        return;
-      case 'repeat':
-        if (_iterator == null) return;
-        _iterator..hasRepeat = false
-            ..repeatModel = null
-            ..repeatPath = null;
-        _scheduleIterator();
-        bindings.remove(name);
-        return;
-      case 'if':
-        if (_iterator == null) return;
-        _iterator..hasIf = false
-            ..ifModel = null
-            ..ifPath = null;
-        _scheduleIterator();
-        bindings.remove(name);
-        return;
-      default:
-        super.unbind(name);
-        return;
-    }
-  }
-
-  void _scheduleIterator() {
-    if (!_iterator.depsChanging) {
-      _iterator.depsChanging = true;
-      scheduleMicrotask(_iterator.resolve);
-    }
+    _iterator._updateDependencies(directives, model);
+    return _iterator;
   }
 
   /**
-   * Creates an instance of the template, using the provided model and optional
-   * binding delegate.
+   * Creates an instance of the template, using the provided [model] and
+   * optional binding [delegate].
+   *
+   * If [instanceBindings] is supplied, each [Bindable] in the returned
+   * instance will be added to the list. This makes it easy to close all of the
+   * bindings without walking the tree. This is not normally necesssary, but is
+   * used internally by the system.
    */
   DocumentFragment createInstance([model, BindingDelegate delegate,
-      List<NodeBinding> bound]) {
-    var ref = templateBind(this.ref);
-    var content = ref.content;
+      List<Bindable> instanceBindings]) {
+
+    final content = templateBind(ref).content;
     // Dart note: we store _bindingMap on the TemplateBindExtension instead of
     // the "content" because we already have an expando for it.
-    var map = ref._bindingMap;
-    if (map == null) {
+    var map = _bindingMap;
+    if (map == null || !identical(map.content, content)) {
       // TODO(rafaelw): Setup a MutationObserver on content to detect
       // when the instanceMap is invalid.
       map = _createInstanceBindingMap(content, delegate);
-      ref._bindingMap = map;
+      map.content = content;
+      _bindingMap = map;
     }
 
-    var staging = _getTemplateStagingDocument();
-    var instance = _deepCloneIgnoreTemplateContent(content, staging);
+    final staging = _getTemplateStagingDocument();
+    final instance = _stagingDocument.createDocumentFragment();
+    _templateCreator[instance] = _node;
 
-    _addMapBindings(instance, map, model, delegate, bound);
-    // TODO(rafaelw): We can do this more lazily, but setting a sentinel
-    // in the parent of the template element, and creating it when it's
-    // asked for by walking back to find the iterating template.
-    _addTemplateInstanceRecord(instance, model);
+    final instanceRecord = new TemplateInstance(model);
+
+    var i = 0;
+    for (var c = content.firstChild; c != null; c = c.nextNode, i++) {
+      final childMap = map != null ? map.getChild(i) : null;
+      var clone = _cloneAndBindInstance(c, instance, _stagingDocument,
+          childMap, model, delegate, instanceBindings);
+      nodeBindFallback(clone)._templateInstance = instanceRecord;
+    }
+
+    instanceRecord._firstNode = instance.firstChild;
+    instanceRecord._lastNode = instance.lastChild;
+
     return instance;
   }
 
@@ -157,19 +121,27 @@
 
   void set bindingDelegate(BindingDelegate value) {
     _bindingDelegate = value;
-    _ensureSetModelScheduled();
+
+    // Clear cached state based on the binding delegate.
+    _bindingMap = null;
+    if (_iterator != null) {
+      _iterator._initPrepareFunctions = false;
+      _iterator._instanceModelFn = null;
+      _iterator._instancePositionChangedFn = null;
+    }
   }
 
   _ensureSetModelScheduled() {
-    if (_scheduled) return;
+    if (_setModelScheduled) return;
     _decorate();
-    _scheduled = true;
+    _setModelScheduled = true;
     scheduleMicrotask(_setModel);
   }
 
   void _setModel() {
-    _scheduled = false;
-    _addBindings(_node, _model, _bindingDelegate);
+    _setModelScheduled = false;
+    var map = _getBindings(_node, _bindingDelegate);
+    _processBindings(_node, map, _model);
   }
 
   /** Gets the template this node refers to. */
@@ -183,6 +155,15 @@
       if (treeScope != null) {
         result = treeScope.getElementById(refId);
       }
+      if (result == null) {
+        var instanceRoot = _getInstanceRoot(_node);
+
+        // TODO(jmesserly): this won't work if refId is a number
+        // Similar to bug: https://github.com/Polymer/ShadowDOM/issues/340
+        if (instanceRoot != null) {
+          result = instanceRoot.querySelector('#$refId');
+        }
+      }
     }
 
     if (result == null) {
@@ -223,25 +204,32 @@
 
     var templateElementExt = this;
     _templateIsDecorated = true;
-    var isNative = _node is TemplateElement;
-    var bootstrapContents = isNative;
-    var liftContents = !isNative;
+    var isNativeHtmlTemplate = _node is TemplateElement;
+    final bootstrapContents = isNativeHtmlTemplate;
+    final liftContents = !isNativeHtmlTemplate;
     var liftRoot = false;
 
-    if (!isNative && _isAttributeTemplate(_node)) {
-      if (instanceRef != null) {
-        // TODO(jmesserly): this is just an assert in TemplateBinding.
-        throw new ArgumentError('instanceRef should not be supplied for '
-            'attribute templates.');
+    if (!isNativeHtmlTemplate) {
+      if (_isAttributeTemplate(_node)) {
+        if (instanceRef != null) {
+          // Dart note: this is just an assert in JS.
+          throw new ArgumentError('instanceRef should not be supplied for '
+              'attribute templates.');
+        }
+        templateElementExt = templateBind(
+            _extractTemplateFromAttributeTemplate(_node));
+        templateElementExt._templateIsDecorated = true;
+        isNativeHtmlTemplate = templateElementExt._node is TemplateElement;
+        liftRoot = true;
+      } else if (_isSvgTemplate(_node)) {
+        templateElementExt = templateBind(
+            _extractTemplateFromSvgTemplate(_node));
+        templateElementExt._templateIsDecorated = true;
+        isNativeHtmlTemplate = templateElementExt._node is TemplateElement;
       }
-      templateElementExt = templateBind(
-          _extractTemplateFromAttributeTemplate(_node));
-      templateElementExt._templateIsDecorated = true;
-      isNative = templateElementExt._node is TemplateElement;
-      liftRoot = true;
-     }
+    }
 
-    if (!isNative) {
+    if (!isNativeHtmlTemplate) {
       var doc = _getOrCreateTemplateContentsOwner(templateElementExt._node);
       templateElementExt._content = doc.createDocumentFragment();
     }
@@ -326,6 +314,16 @@
     return template;
   }
 
+  static Element _extractTemplateFromSvgTemplate(Element el) {
+    var template = el.ownerDocument.createElement('template');
+    el.parentNode.insertBefore(template, el);
+    template.attributes.addAll(el.attributes);
+
+    el.attributes.clear();
+    el.remove();
+    return template;
+  }
+
   static void _liftNonNativeChildrenIntoContent(TemplateBindExtension template,
       Element el, bool useRoot) {
 
@@ -386,58 +384,19 @@
   }
 }
 
-// TODO(jmesserly): https://github.com/polymer/templatebinding uses
-// TemplateIterator as the binding. This is a nice performance optimization,
-// however it means it doesn't share any of the reflective APIs with
-// NodeBinding: https://github.com/Polymer/TemplateBinding/issues/147
-class _TemplateBinding implements NodeBinding {
-  TemplateBindExtension _ext;
-  Object _model;
-  final String property;
-  final String path;
-
-  Node get node => _ext._node;
-
-  get model => _model;
-
-  bool get closed => _ext == null;
-
-  get value => _observer.value;
-
-  set value(newValue) {
-    _observer.value = newValue;
-  }
-
-  // No need to cache this since we only have it to support get/set value.
-  get _observer {
-    if ((_model is PathObserver || _model is CompoundPathObserver) &&
-        path == 'value') {
-      return _model;
-    }
-    return new PathObserver(_model, path);
-  }
-
-  _TemplateBinding(this._ext, this.property, this._model, this.path);
-
-  void valueChanged(newValue) {}
-
-  sanitizeBoundValue(value) => value == null ? '' : '$value';
-
-  void close() {
-    if (closed) return;
-
-    // TODO(jmesserly): unlike normal NodeBinding.close methods this will remove
-    // the binding from _node.bindings. Is that okay?
-    _ext.unbind(property);
-
-    _model = null;
-    _ext = null;
-  }
-}
+final _templateCreator = new Expando();
 
 _getTreeScope(Node node) {
-  while (node.parentNode != null) {
-    node = node.parentNode;
+  while (true) {
+    var parent = node.parentNode;
+    if (parent != null) {
+      node = parent;
+    } else {
+      var creator = _templateCreator[node];
+      if (creator == null) break;
+
+      node = creator;
+    }
   }
 
   // Note: JS code tests that getElementById is present. We can't do that
@@ -447,3 +406,10 @@
   }
   return null;
 }
+
+_getInstanceRoot(node) {
+  while (node.parentNode != null) {
+    node = node.parentNode;
+  }
+  return _templateCreator[node] != null ? node : null;
+}
diff --git a/pkg/template_binding/lib/src/template_iterator.dart b/pkg/template_binding/lib/src/template_iterator.dart
index c87306a..66d44f5 100644
--- a/pkg/template_binding/lib/src/template_iterator.dart
+++ b/pkg/template_binding/lib/src/template_iterator.dart
@@ -17,23 +17,23 @@
 // See: https://github.com/polymer/TemplateBinding/issues/59
 bool _toBoolean(value) => null != value && false != value;
 
-List _getBindings(Node node, BindingDelegate delegate) {
+_InstanceBindingMap _getBindings(Node node, BindingDelegate delegate) {
   if (node is Element) {
     return _parseAttributeBindings(node, delegate);
   }
 
   if (node is Text) {
-    var tokens = _parseMustaches(node.text, 'text', node, delegate);
-    if (tokens != null) return ['text', tokens];
+    var tokens = MustacheTokens.parse(node.text, 'text', node, delegate);
+    if (tokens != null) return new _InstanceBindingMap(['text', tokens]);
   }
 
   return null;
 }
 
 void _addBindings(Node node, model, [BindingDelegate delegate]) {
-  var bindings = _getBindings(node, delegate);
+  final bindings = _getBindings(node, delegate);
   if (bindings != null) {
-    _processBindings(bindings, node, model);
+    _processBindings(node, bindings, model);
   }
 
   for (var c = node.firstChild; c != null; c = c.nextNode) {
@@ -41,8 +41,17 @@
   }
 }
 
+MustacheTokens _parseWithDefault(Element element, String name,
+    BindingDelegate delegate) {
 
-List _parseAttributeBindings(Element element, BindingDelegate delegate) {
+  var v = element.attributes[name];
+  if (v == '') v = '{{}}';
+  return MustacheTokens.parse(v, name, element, delegate);
+}
+
+_InstanceBindingMap _parseAttributeBindings(Element element,
+    BindingDelegate delegate) {
+
   var bindings = null;
   var ifFound = false;
   var bindFound = false;
@@ -58,193 +67,157 @@
       name = name.substring(1);
     }
 
-    if (isTemplateNode) {
-      if (name == 'if') {
-        ifFound = true;
-        if (value == '') value = '{{}}'; // Accept 'naked' if.
-      } else if (name == 'bind' || name == 'repeat') {
-        bindFound = true;
-        if (value == '') value = '{{}}'; // Accept 'naked' bind & repeat.
-      }
+    if (isTemplateNode &&
+        (name == 'bind' || name == 'if' || name == 'repeat')) {
+      return;
     }
 
-    var tokens = _parseMustaches(value, name, element, delegate);
+    var tokens = MustacheTokens.parse(value, name, element, delegate);
     if (tokens != null) {
       if (bindings == null) bindings = [];
       bindings..add(name)..add(tokens);
     }
   });
 
-  // Treat <template if> as <template bind if>
-  if (ifFound && !bindFound) {
+  if (isTemplateNode) {
     if (bindings == null) bindings = [];
-    bindings..add('bind')
-        ..add(_parseMustaches('{{}}', 'bind', element, delegate));
+    var result = new _TemplateBindingMap(bindings)
+        .._if = _parseWithDefault(element, 'if', delegate)
+        .._bind = _parseWithDefault(element, 'bind', delegate)
+        .._repeat = _parseWithDefault(element, 'repeat', delegate);
+
+    // Treat <template if> as <template bind if>
+    if (result._if != null && result._bind == null && result._repeat == null) {
+      result._bind = MustacheTokens.parse('{{}}', 'bind', element, delegate);
+    }
+
+    return result;
   }
 
-  return bindings;
+  return bindings == null ? null : new _InstanceBindingMap(bindings);
 }
 
-void _processBindings(List bindings, Node node, model,
-    [List<NodeBinding> bound]) {
+_processOneTimeBinding(String name, MustacheTokens tokens, Node node, model) {
 
+  if (tokens.hasOnePath) {
+    var delegateFn = tokens.getPrepareBinding(0);
+    var value = delegateFn != null ? delegateFn(model, node, true) :
+        tokens.getPath(0).getValueFrom(model);
+    return tokens.isSimplePath ? value : tokens.combinator(value);
+  }
+
+  // Tokens uses a striding scheme to essentially store a sequence of structs in
+  // the list. See _MustacheTokens for more information.
+  var values = new List(tokens.length);
+  for (int i = 0; i < tokens.length; i++) {
+    Function delegateFn = tokens.getPrepareBinding(i);
+    values[i] = delegateFn != null ?
+        delegateFn(model, node, false) :
+        tokens.getPath(i).getValueFrom(model);
+  }
+  return tokens.combinator(values);
+}
+
+_processSinglePathBinding(String name, MustacheTokens tokens, Node node,
+    model) {
+  Function delegateFn = tokens.getPrepareBinding(0);
+  var observer = delegateFn != null ?
+      delegateFn(model, node, false) :
+      new PathObserver(model, tokens.getPath(0));
+
+  return tokens.isSimplePath ? observer :
+      new ObserverTransform(observer, tokens.combinator);
+}
+
+_processBinding(String name, MustacheTokens tokens, Node node, model) {
+  if (tokens.onlyOneTime) {
+    return _processOneTimeBinding(name, tokens, node, model);
+  }
+  if (tokens.hasOnePath) {
+    return _processSinglePathBinding(name, tokens, node, model);
+  }
+
+  var observer = new CompoundObserver();
+
+  for (int i = 0; i < tokens.length; i++) {
+    bool oneTime = tokens.getOneTime(i);
+    Function delegateFn = tokens.getPrepareBinding(i);
+
+    if (delegateFn != null) {
+      var value = delegateFn(model, node, oneTime);
+      if (oneTime) {
+        observer.addPath(value);
+      } else {
+        observer.addObserver(value);
+      }
+      continue;
+    }
+
+    PropertyPath path = tokens.getPath(i);
+    if (oneTime) {
+      observer.addPath(path.getValueFrom(model));
+    } else {
+      observer.addPath(model, path);
+    }
+  }
+
+  return new ObserverTransform(observer, tokens.combinator);
+}
+
+void _processBindings(Node node, _InstanceBindingMap map, model,
+    [List<Bindable> instanceBindings]) {
+
+  final bindings = map.bindings;
   for (var i = 0; i < bindings.length; i += 2) {
     var name = bindings[i];
     var tokens = bindings[i + 1];
-    var bindingModel = model;
-    var bindingPath = tokens.tokens[1];
-    if (tokens.hasOnePath) {
-      var delegateFn = tokens.tokens[2];
-      if (delegateFn != null) {
-        var delegateBinding = delegateFn(model, node);
-        if (delegateBinding != null) {
-          bindingModel = delegateBinding;
-          bindingPath = 'value';
-        }
-      }
 
-      if (!tokens.isSimplePath) {
-        bindingModel = new PathObserver(bindingModel, bindingPath,
-            computeValue: tokens.combinator);
-        bindingPath = 'value';
-      }
-    } else {
-      var observer = new CompoundPathObserver(computeValue: tokens.combinator);
-      for (var j = 1; j < tokens.tokens.length; j += 3) {
-        var subModel = model;
-        var subPath = tokens.tokens[j];
-        var delegateFn = tokens.tokens[j + 1];
-        var delegateBinding = delegateFn != null ?
-            delegateFn(subModel, node) : null;
-
-        if (delegateBinding != null) {
-          subModel = delegateBinding;
-          subPath = 'value';
-        }
-
-        observer.addPath(subModel, subPath);
-      }
-
-      observer.start();
-      bindingModel = observer;
-      bindingPath = 'value';
+    var value = _processBinding(name, tokens, node, model);
+    var binding = nodeBind(node).bind(name, value, oneTime: tokens.onlyOneTime);
+    if (binding != null && instanceBindings != null) {
+      instanceBindings.add(binding);
     }
+  }
 
-    var binding = nodeBind(node).bind(name, bindingModel, bindingPath);
-    if (bound != null) bound.add(binding);
+  if (map is! _TemplateBindingMap) return;
+
+  final templateExt = nodeBindFallback(node);
+  templateExt._model = model;
+
+  var iter = templateExt._processBindingDirectives(map);
+  if (iter != null && instanceBindings != null) {
+    instanceBindings.add(iter);
   }
 }
 
-/**
- * Parses {{ mustache }} bindings.
- *
- * Returns null if there are no matches. Otherwise returns the parsed tokens.
- */
-_MustacheTokens _parseMustaches(String s, String name, Node node,
-    BindingDelegate delegate) {
-  if (s.isEmpty) return null;
 
-  var tokens = null;
-  var length = s.length;
-  var startIndex = 0, lastIndex = 0, endIndex = 0;
-  while (lastIndex < length) {
-    startIndex = s.indexOf('{{', lastIndex);
-    endIndex = startIndex < 0 ? -1 : s.indexOf('}}', startIndex + 2);
-
-    if (endIndex < 0) {
-      if (tokens == null) return null;
-
-      tokens.add(s.substring(lastIndex)); // TEXT
-      break;
-    }
-
-    if (tokens == null) tokens = [];
-    tokens.add(s.substring(lastIndex, startIndex)); // TEXT
-    var pathString = s.substring(startIndex + 2, endIndex).trim();
-    tokens.add(pathString); // PATH
-    var delegateFn = delegate == null ? null :
-        delegate.prepareBinding(pathString, name, node);
-    tokens.add(delegateFn);
-
-    lastIndex = endIndex + 2;
-  }
-
-  if (lastIndex == length) tokens.add('');
-
-  return new _MustacheTokens(tokens);
-}
-
-class _MustacheTokens {
-  bool get hasOnePath => tokens.length == 4;
-  bool get isSimplePath => hasOnePath && tokens[0] == '' && tokens[3] == '';
-
-  /** [TEXT, (PATH, TEXT, DELEGATE_FN)+] if there is at least one mustache. */
-  // TODO(jmesserly): clean up the type here?
-  final List tokens;
-
-  // Dart note: I think this is cached in JavaScript to avoid an extra
-  // allocation per template instance. Seems reasonable, so we do the same.
-  Function _combinator;
-  Function get combinator => _combinator;
-
-  _MustacheTokens(this.tokens) {
-    // Should be: [TEXT, (PATH, TEXT, DELEGATE_FN)+].
-    assert((tokens.length + 2) % 3 == 0);
-
-    _combinator = hasOnePath ? _singleCombinator : _listCombinator;
-  }
-
-  // Dart note: split "combinator" into the single/list variants, so the
-  // argument can be typed.
-  String _singleCombinator(Object value) {
-    if (value == null) value = '';
-    return '${tokens[0]}$value${tokens[3]}';
-  }
-
-  String _listCombinator(List<Object> values) {
-    var newValue = new StringBuffer(tokens[0]);
-    for (var i = 1; i < tokens.length; i += 3) {
-      var value = values[(i - 1) ~/ 3];
-      if (value != null) newValue.write(value);
-      newValue.write(tokens[i + 2]);
-    }
-
-    return newValue.toString();
-  }
-}
-
-void _addTemplateInstanceRecord(fragment, model) {
-  if (fragment.firstChild == null) {
-    return;
-  }
-
-  var instanceRecord = new TemplateInstance(
-      fragment.firstChild, fragment.lastChild, model);
-
-  var node = instanceRecord.firstNode;
-  while (node != null) {
-    nodeBindFallback(node)._templateInstance = instanceRecord;
-    node = node.nextNode;
-  }
-}
-
-class _TemplateIterator {
+// Note: this doesn't really implement most of Bindable. See:
+// https://github.com/Polymer/TemplateBinding/issues/147
+class _TemplateIterator extends Bindable {
   final TemplateBindExtension _templateExt;
 
   /**
    * Flattened array of tuples:
    * <instanceTerminatorNode, [bindingsSetupByInstance]>
    */
-  final List terminators = [];
-  List iteratedValue;
-  bool closed = false;
-  bool depsChanging = false;
+  final List _terminators = [];
 
-  bool hasRepeat = false, hasBind = false, hasIf = false;
-  Object repeatModel, bindModel, ifModel;
-  String repeatPath, bindPath, ifPath;
+  /** A copy of the last rendered [_presentValue] list state. */
+  final List _iteratedValue = [];
 
-  StreamSubscription _valueSub, _listSub;
+  List _presentValue;
+
+  bool _closed = false;
+
+  // Dart note: instead of storing these in a Map like JS, or using a separate
+  // object (extra memory overhead) we just inline the fields.
+  var _ifValue, _value;
+
+  // TODO(jmesserly): lots of booleans in this object. Bitmask?
+  bool _hasIf, _hasRepeat;
+  bool _ifOneTime, _oneTime;
+
+  StreamSubscription _listSub;
 
   bool _initPrepareFunctions = false;
   PrepareInstanceModelFunction _instanceModelFn;
@@ -252,81 +225,106 @@
 
   _TemplateIterator(this._templateExt);
 
+  open(callback) => throw new StateError('binding already opened');
+  get value => _value;
+
   Element get _templateElement => _templateExt._node;
 
-  resolve() {
-    depsChanging = false;
-
-    if (_valueSub != null) {
-      _valueSub.cancel();
-      _valueSub = null;
+  void _closeDependencies() {
+    if (_ifValue is Bindable) {
+      _ifValue.close();
+      _ifValue = null;
     }
-
-    if (!hasRepeat && !hasBind) {
-      _valueChanged(null);
-      return;
+    if (_value is Bindable) {
+      _value.close();
+      _value = null;
     }
+  }
 
-    final model = hasRepeat ? repeatModel : bindModel;
-    final path = hasRepeat ? repeatPath : bindPath;
+  void _updateDependencies(_TemplateBindingMap directives, model) {
+    _closeDependencies();
 
-    var valueObserver;
-    if (!hasIf) {
-      valueObserver = new PathObserver(model, path,
-          computeValue: hasRepeat ? null : (x) => [x]);
-    } else {
-      // TODO(jmesserly): I'm not sure if closing over this is necessary for
-      // correctness. It does seem useful if the valueObserver gets fired after
-      // hasRepeat has changed, due to async nature of things.
-      final isRepeat = hasRepeat;
+    final template = _templateElement;
 
-      valueFn(List values) {
-        var modelValue = values[0];
-        var ifValue = values[1];
-        if (!_toBoolean(ifValue)) return null;
-        return isRepeat ? modelValue : [ modelValue ];
+    _hasIf = directives._if != null;
+    _hasRepeat = directives._repeat != null;
+
+    if (_hasIf) {
+      _ifOneTime = directives._if.onlyOneTime;
+      _ifValue = _processBinding('if', directives._if, template, model);
+
+      // oneTime if & predicate is false. nothing else to do.
+      if (_ifOneTime) {
+        if (!_toBoolean(_ifValue)) {
+          _updateIteratedValue(null);
+          return;
+        }
+      } else {
+        (_ifValue as Bindable).open(_updateIteratedValue);
       }
-
-      valueObserver = new CompoundPathObserver(computeValue: valueFn)
-          ..addPath(model, path)
-          ..addPath(ifModel, ifPath)
-          ..start();
     }
 
-    _valueSub = valueObserver.changes.listen(
-        (r) => _valueChanged(r.last.newValue));
-    _valueChanged(valueObserver.value);
-  }
-
-  void _valueChanged(newValue) {
-    var oldValue = iteratedValue;
-    unobserve();
-
-    if (newValue is List) {
-      iteratedValue = newValue;
-    } else if (newValue is Iterable) {
-      // Dart note: we support Iterable by calling toList.
-      // But we need to be careful to observe the original iterator if it
-      // supports that.
-      iteratedValue = (newValue as Iterable).toList();
+    if (_hasRepeat) {
+      _oneTime = directives._repeat.onlyOneTime;
+      _value = _processBinding('repeat', directives._repeat, template, model);
     } else {
-      iteratedValue = null;
+      _oneTime = directives._bind.onlyOneTime;
+      _value = _processBinding('bind', directives._bind, template, model);
     }
 
-    if (iteratedValue != null && newValue is ObservableList) {
-      _listSub = newValue.listChanges.listen(_handleSplices);
-    }
+    if (!_oneTime) _value.open(_updateIteratedValue);
 
-    var splices = ObservableList.calculateChangeRecords(
-        oldValue != null ? oldValue : [],
-        iteratedValue != null ? iteratedValue : []);
-
-    if (splices.isNotEmpty) _handleSplices(splices);
+    _updateIteratedValue(null);
   }
 
-  Node getTerminatorAt(int index) {
+  void _updateIteratedValue(_) {
+    if (_hasIf) {
+      var ifValue = _ifValue;
+      if (!_ifOneTime) ifValue = (ifValue as Bindable).value;
+      if (!_toBoolean(ifValue)) {
+        _valueChanged([]);
+        return;
+      }
+    }
+
+    var value = _value;
+    if (!_oneTime) value = (value as Bindable).value;
+    if (!_hasRepeat) value = [value];
+    _valueChanged(value);
+  }
+
+  void _valueChanged(Object value) {
+    if (value is! List) {
+      if (value is Iterable) {
+        // Dart note: we support Iterable by calling toList.
+        // But we need to be careful to observe the original iterator if it
+        // supports that.
+        value = (value as Iterable).toList();
+      } else {
+        value = [];
+      }
+    }
+
+    if (identical(value, _iteratedValue)) return;
+
+    _unobserve();
+    _presentValue = value;
+
+    if (value is ObservableList && _hasRepeat && !_oneTime) {
+      // Make sure any pending changes aren't delivered, since we're getting
+      // a snapshot at this point in time.
+      value.discardListChages();
+      _listSub = value.listChanges.listen(_handleSplices);
+    }
+
+    _handleSplices(ObservableList.calculateChangeRecords(
+        _iteratedValue != null ? _iteratedValue : [],
+        _presentValue != null ? _presentValue : []));
+  }
+
+  Node _getTerminatorAt(int index) {
     if (index == -1) return _templateElement;
-    var terminator = terminators[index * 2];
+    var terminator = _terminators[index * 2];
     if (!isSemanticTemplate(terminator) ||
         identical(terminator, _templateElement)) {
       return terminator;
@@ -335,15 +333,15 @@
     var subIter = templateBindFallback(terminator)._iterator;
     if (subIter == null) return terminator;
 
-    return subIter.getTerminatorAt(subIter.terminators.length ~/ 2 - 1);
+    return subIter._getTerminatorAt(subIter._terminators.length ~/ 2 - 1);
   }
 
   // TODO(rafaelw): If we inserting sequences of instances we can probably
-  // avoid lots of calls to getTerminatorAt(), or cache its result.
-  void insertInstanceAt(int index, DocumentFragment fragment,
-        List<Node> instanceNodes, List<NodeBinding> bound) {
+  // avoid lots of calls to _getTerminatorAt(), or cache its result.
+  void _insertInstanceAt(int index, DocumentFragment fragment,
+        List<Node> instanceNodes, List<Bindable> instanceBindings) {
 
-    var previousTerminator = getTerminatorAt(index - 1);
+    var previousTerminator = _getTerminatorAt(index - 1);
     var terminator = null;
     if (fragment != null) {
       terminator = fragment.lastChild;
@@ -352,7 +350,7 @@
     }
     if (terminator == null) terminator = previousTerminator;
 
-    terminators.insertAll(index * 2, [terminator, bound]);
+    _terminators.insertAll(index * 2, [terminator, instanceBindings]);
     var parent = _templateElement.parentNode;
     var insertBeforeNode = previousTerminator.nextNode;
 
@@ -365,12 +363,12 @@
     }
   }
 
-  _BoundNodes extractInstanceAt(int index) {
+  _BoundNodes _extractInstanceAt(int index) {
     var instanceNodes = <Node>[];
-    var previousTerminator = getTerminatorAt(index - 1);
-    var terminator = getTerminatorAt(index);
-    var bound = terminators[index * 2 + 1];
-    terminators.removeRange(index * 2, index * 2 + 2);
+    var previousTerminator = _getTerminatorAt(index - 1);
+    var terminator = _getTerminatorAt(index);
+    var instanceBindings = _terminators[index * 2 + 1];
+    _terminators.removeRange(index * 2, index * 2 + 2);
 
     var parent = _templateElement.parentNode;
     while (terminator != previousTerminator) {
@@ -379,24 +377,28 @@
       node.remove();
       instanceNodes.add(node);
     }
-    return new _BoundNodes(instanceNodes, bound);
+    return new _BoundNodes(instanceNodes, instanceBindings);
   }
 
   void _handleSplices(List<ListChangeRecord> splices) {
-    if (closed) return;
+    if (_closed || splices.isEmpty) return;
 
     final template = _templateElement;
-    final delegate = _templateExt._self.bindingDelegate;
 
-    if (template.parentNode == null || template.ownerDocument.window == null) {
+    if (template.parentNode == null) {
       close();
       return;
     }
 
+    ObservableList.applyChangeRecords(_iteratedValue, _presentValue, splices);
+
+    final delegate = _templateExt.bindingDelegate;
+
     // Dart note: the JavaScript code relies on the distinction between null
     // and undefined to track whether the functions are prepared. We use a bool.
     if (!_initPrepareFunctions) {
       _initPrepareFunctions = true;
+      final delegate = _templateExt._self.bindingDelegate;
       if (delegate != null) {
         _instanceModelFn = delegate.prepareInstanceModel(template);
         _instancePositionChangedFn =
@@ -408,7 +410,7 @@
     var removeDelta = 0;
     for (var splice in splices) {
       for (var model in splice.removed) {
-        instanceCache[model] = extractInstanceAt(splice.index + removeDelta);
+        instanceCache[model] = _extractInstanceAt(splice.index + removeDelta);
       }
 
       removeDelta -= splice.addedCount;
@@ -419,38 +421,39 @@
           addIndex < splice.index + splice.addedCount;
           addIndex++) {
 
-        var model = iteratedValue[addIndex];
+        var model = _iteratedValue[addIndex];
         var fragment = null;
         var instance = instanceCache.remove(model);
-        List bound;
+        List instanceBindings;
         List instanceNodes = null;
         if (instance != null && instance.nodes.isNotEmpty) {
-          bound = instance.bound;
+          instanceBindings = instance.instanceBindings;
           instanceNodes = instance.nodes;
         } else {
-          bound = [];
+          instanceBindings = [];
           if (_instanceModelFn != null) {
             model = _instanceModelFn(model);
           }
           if (model != null) {
-            fragment = _templateExt.createInstance(model, delegate, bound);
+            fragment = _templateExt.createInstance(model, delegate,
+                instanceBindings);
           }
         }
 
-        insertInstanceAt(addIndex, fragment, instanceNodes, bound);
+        _insertInstanceAt(addIndex, fragment, instanceNodes, instanceBindings);
       }
     }
 
     for (var instance in instanceCache.values) {
-      closeInstanceBindings(instance.bound);
+      _closeInstanceBindings(instance.instanceBindings);
     }
 
-    if (_instancePositionChangedFn != null) reportInstancesMoved(splices);
+    if (_instancePositionChangedFn != null) _reportInstancesMoved(splices);
   }
 
-  void reportInstanceMoved(int index) {
-    var previousTerminator = getTerminatorAt(index - 1);
-    var terminator = getTerminatorAt(index);
+  void _reportInstanceMoved(int index) {
+    var previousTerminator = _getTerminatorAt(index - 1);
+    var terminator = _getTerminatorAt(index);
     if (identical(previousTerminator, terminator)) {
       return; // instance has zero nodes.
     }
@@ -463,13 +466,13 @@
     _instancePositionChangedFn(instance, index);
   }
 
-  void reportInstancesMoved(List<ListChangeRecord> splices) {
+  void _reportInstancesMoved(List<ListChangeRecord> splices) {
     var index = 0;
     var offset = 0;
     for (var splice in splices) {
       if (offset != 0) {
         while (index < splice.index) {
-          reportInstanceMoved(index);
+          _reportInstanceMoved(index);
           index++;
         }
       } else {
@@ -477,7 +480,7 @@
       }
 
       while (index < splice.index + splice.addedCount) {
-        reportInstanceMoved(index);
+        _reportInstanceMoved(index);
         index++;
       }
 
@@ -486,44 +489,41 @@
 
     if (offset == 0) return;
 
-    var length = terminators.length ~/ 2;
+    var length = _terminators.length ~/ 2;
     while (index < length) {
-      reportInstanceMoved(index);
+      _reportInstanceMoved(index);
       index++;
     }
   }
 
-  void closeInstanceBindings(List<NodeBinding> bound) {
-    for (var binding in bound) binding.close();
+  void _closeInstanceBindings(List<Bindable> instanceBindings) {
+    for (var binding in instanceBindings) binding.close();
   }
 
-  void unobserve() {
+  void _unobserve() {
     if (_listSub == null) return;
     _listSub.cancel();
     _listSub = null;
   }
 
   void close() {
-    if (closed) return;
+    if (_closed) return;
 
-    unobserve();
-    for (var i = 1; i < terminators.length; i += 2) {
-      closeInstanceBindings(terminators[i]);
+    _unobserve();
+    for (var i = 1; i < _terminators.length; i += 2) {
+      _closeInstanceBindings(_terminators[i]);
     }
 
-    terminators.clear();
-    if (_valueSub != null) {
-      _valueSub.cancel();
-      _valueSub = null;
-    }
+    _terminators.clear();
+    _closeDependencies();
     _templateExt._iterator = null;
-    closed = true;
+    _closed = true;
   }
 }
 
 // Dart note: the JavaScript version just puts an expando on the array.
 class _BoundNodes {
   final List<Node> nodes;
-  final List<NodeBinding> bound;
-  _BoundNodes(this.nodes, this.bound);
+  final List<Bindable> instanceBindings;
+  _BoundNodes(this.nodes, this.instanceBindings);
 }
diff --git a/pkg/template_binding/lib/src/text.dart b/pkg/template_binding/lib/src/text.dart
index ecb2581..fd4c44a 100644
--- a/pkg/template_binding/lib/src/text.dart
+++ b/pkg/template_binding/lib/src/text.dart
@@ -8,20 +8,25 @@
 class _TextExtension extends NodeBindExtension {
   _TextExtension(Text node) : super._(node);
 
-  NodeBinding bind(String name, model, [String path]) {
+  Bindable bind(String name, value, {bool oneTime: false}) {
     // Dart note: 'text' instead of 'textContent' to match the DOM property.
     if (name != 'text') {
-      return super.bind(name, model, path);
+      return super.bind(name, value, oneTime: oneTime);
     }
+    if (oneTime) {
+      _updateText(value);
+      return null;
+    }
+
     unbind(name);
-    return bindings[name] = new _TextBinding(_node, model, path);
+    _open(value, _updateText);
+    return bindings[name] = value;
+  }
+
+  _updateText(value) {
+    _node.text = _sanitizeValue(value);
   }
 }
 
-class _TextBinding extends NodeBinding {
-  _TextBinding(node, model, path) : super(node, 'text', model, path);
-
-  void valueChanged(newValue) {
-    node.text = sanitizeBoundValue(newValue);
-  }
-}
+/** Called to sanitize the value before it is assigned into the property. */
+_sanitizeValue(value) => value == null ? '' : '$value';
diff --git a/pkg/template_binding/lib/src/text_area_element.dart b/pkg/template_binding/lib/src/text_area_element.dart
index 0d462d1..361f7c1 100644
--- a/pkg/template_binding/lib/src/text_area_element.dart
+++ b/pkg/template_binding/lib/src/text_area_element.dart
@@ -10,11 +10,16 @@
 
   TextAreaElement get _node => super._node;
 
-  NodeBinding bind(String name, model, [String path]) {
-    if (name != 'value') return super.bind(name, model, path);
+  Bindable bind(String name, value, {bool oneTime: false}) {
+    if (name != 'value') return super.bind(name, value, oneTime: oneTime);
+
+    if (oneTime) {
+      _InputBinding._updateProperty(_node, value, name);
+      return null;
+    }
 
     _self.unbind(name);
     _node.attributes.remove(name);
-    return bindings[name] = new _ValueBinding(_node, model, path);
+    return bindings[name] = new _InputBinding(_node, value, name);
   }
 }
diff --git a/pkg/template_binding/lib/template_binding.dart b/pkg/template_binding/lib/template_binding.dart
index 61ec19d..97daeab 100644
--- a/pkg/template_binding/lib/template_binding.dart
+++ b/pkg/template_binding/lib/template_binding.dart
@@ -25,10 +25,9 @@
 import 'package:observe/observe.dart';
 
 import 'src/binding_delegate.dart';
-import 'src/node_binding.dart';
+import 'src/mustache_tokens.dart';
 
 export 'src/binding_delegate.dart';
-export 'src/node_binding.dart' show NodeBinding;
 
 part 'src/element.dart';
 part 'src/input_bindings.dart';
@@ -45,6 +44,8 @@
 // two packages, but this is not easy when we are faking extension methods.
 // Since TemplateElement needs to override Node.bind, it seems like the
 // Node.bind layer must have some innate knowledge of TemplateBinding.
+// NOTE: I've heard NodeBind might become an internal API, which is all the more
+// reason to have it in this package.
 
 /**
  * Provides access to the data binding APIs for the [node]. For example:
@@ -136,6 +137,12 @@
 bool _isAttributeTemplate(Element n) => n.attributes.containsKey('template') &&
     _SEMANTIC_TEMPLATE_TAGS.containsKey(n.localName);
 
+bool _isSvgTemplate(Element el) => el.tagName == 'template' &&
+    el.namespaceUri == 'http://www.w3.org/2000/svg';
+
+bool _isHtmlTemplate(Element el) => el.tagName == 'TEMPLATE' &&
+    el.namespaceUri == 'http://www.w3.org/1999/xhtml';
+
 /**
  * Returns true if this node is semantically a template.
  *
@@ -146,7 +153,7 @@
  * and COL), OPTION, and OPTGROUP.
  */
 bool isSemanticTemplate(Node n) => n is Element &&
-    (n.localName == 'template' || _isAttributeTemplate(n));
+    (_isHtmlTemplate(n) || _isAttributeTemplate(n) || _isSvgTemplate(n));
 
 // TODO(jmesserly): const set would be better
 const _SEMANTIC_TEMPLATE_TAGS = const {
diff --git a/pkg/template_binding/pubspec.yaml b/pkg/template_binding/pubspec.yaml
index 873e79d..b4a1685 100644
--- a/pkg/template_binding/pubspec.yaml
+++ b/pkg/template_binding/pubspec.yaml
@@ -1,5 +1,5 @@
 name: template_binding
-version: 0.9.1
+version: 0.10.0-dev
 author: Polymer.dart Team <web-ui-dev@dartlang.org>
 description: >
   Extends the capabilities of the HTML Template Element by enabling it to
@@ -8,7 +8,7 @@
 dependencies:
   logging: ">=0.9.0 <0.10.0"
   mutation_observer: ">=0.9.0 <0.10.0"
-  observe: ">=0.9.0 <0.10.0"
+  observe: ">=0.10.0-dev <0.11.0"
 dev_dependencies:
   custom_element: ">=0.9.1 <0.10.0"
   unittest: ">=0.9.0 <0.10.0"
diff --git a/pkg/template_binding/test/binding_syntax.dart b/pkg/template_binding/test/binding_syntax.dart
index 384dbf9..f5e6afd9 100644
--- a/pkg/template_binding/test/binding_syntax.dart
+++ b/pkg/template_binding/test/binding_syntax.dart
@@ -4,18 +4,18 @@
 
 library template_binding.test.binding_syntax;
 
+import 'dart:async';
 import 'dart:collection';
 import 'dart:html';
 import 'package:template_binding/template_binding.dart';
 import 'package:observe/observe.dart';
-import 'package:unittest/html_config.dart';
 import 'package:unittest/unittest.dart';
 import 'utils.dart';
 
 // Note: this test is executed by template_element_test.dart
 
 syntaxTests(FooBarModel fooModel([foo, bar])) {
-  observeTest('prepareBinding', () {
+  test('prepareBinding', () {
     var model = fooModel('bar');
     var testSyntax = new TestBindingSyntax();
     var div = createTestHtml(
@@ -23,23 +23,24 @@
           '<template bind>{{ foo }}</template>'
         '</template>');
     recursivelySetTemplateModel(div, model, testSyntax);
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
-    expect(div.nodes.last.text, 'bar');
-    expect(div.nodes[2].tagName, 'TEMPLATE');
-    expect(testSyntax.log, [
-      ['prepare', '', 'bind', 'TEMPLATE'],
-      ['bindFn', model, 'TEMPLATE', 0],
-      ['prepare', 'foo', 'text', 'TEXT'],
-      ['prepare', '', 'bind', 'TEMPLATE'],
-      ['bindFn', model, 'TEXT', 2],
-      ['bindFn', model, 'TEMPLATE', 3],
-      ['prepare', 'foo', 'text', 'TEXT'],
-      ['bindFn', model, 'TEXT', 6],
-    ]);
+    return new Future(() {
+      expect(div.nodes.length, 4);
+      expect(div.nodes.last.text, 'bar');
+      expect(div.nodes[2].tagName, 'TEMPLATE');
+      expect(testSyntax.log, [
+        ['prepare', '', 'bind', 'TEMPLATE'],
+        ['bindFn', model, 'TEMPLATE', 0],
+        ['prepare', 'foo', 'text', 'TEXT'],
+        ['prepare', '', 'bind', 'TEMPLATE'],
+        ['bindFn', model, 'TEXT', 2],
+        ['bindFn', model, 'TEMPLATE', 3],
+        ['prepare', 'foo', 'text', 'TEXT'],
+        ['bindFn', model, 'TEXT', 6],
+      ]);
+    });
   });
 
-  observeTest('prepareInstanceModel', () {
+  test('prepareInstanceModel', () {
     var model = toObservable([fooModel(1), fooModel(2), fooModel(3)]);
 
     var testSyntax = new TestModelSyntax();
@@ -49,23 +50,24 @@
 
     var template = div.nodes[0];
     recursivelySetTemplateModel(div, model, testSyntax);
-    performMicrotaskCheckpoint();
+    return new Future(() {
 
-    expect(div.nodes.length, 4);
-    expect(div.nodes[0].tagName, 'TEMPLATE');
-    expect(div.nodes[1].text, 'a');
-    expect(div.nodes[2].text, 'b');
-    expect(div.nodes[3].text, 'c');
+      expect(div.nodes.length, 4);
+      expect(div.nodes[0].tagName, 'TEMPLATE');
+      expect(div.nodes[1].text, 'a');
+      expect(div.nodes[2].text, 'b');
+      expect(div.nodes[3].text, 'c');
 
-    expect(testSyntax.log, [
-      ['prepare', template],
-      ['bindFn', model[0]],
-      ['bindFn', model[1]],
-      ['bindFn', model[2]],
-    ]);
+      expect(testSyntax.log, [
+        ['prepare', template],
+        ['bindFn', model[0]],
+        ['bindFn', model[1]],
+        ['bindFn', model[2]],
+      ]);
+    });
   });
 
-  observeTest('prepareInstanceModel - reorder instances', () {
+  test('prepareInstanceModel - reorder instances', () {
     var model = toObservable([0, 1, 2]);
 
     var div = createTestHtml('<template repeat>{{}}</template>');
@@ -73,18 +75,19 @@
     var delegate = new TestInstanceModelSyntax();
 
     recursivelySetTemplateModel(div, model, delegate);
-    performMicrotaskCheckpoint();
-    expect(delegate.prepareCount, 1);
-    expect(delegate.callCount, 3);
+    return new Future(() {
+      expect(delegate.prepareCount, 1);
+      expect(delegate.callCount, 3);
 
-    // Note: intentionally mutate in place.
-    model.replaceRange(0, model.length, model.reversed.toList());
-    performMicrotaskCheckpoint();
-    expect(delegate.prepareCount, 1);
-    expect(delegate.callCount, 3);
+      // Note: intentionally mutate in place.
+      model.replaceRange(0, model.length, model.reversed.toList());
+    }).then(endOfMicrotask).then((_) {
+      expect(delegate.prepareCount, 1);
+      expect(delegate.callCount, 3);
+    });
   });
 
-  observeTest('prepareInstancePositionChanged', () {
+  test('prepareInstancePositionChanged', () {
     var model = toObservable(['a', 'b', 'c']);
 
     var div = createTestHtml('<template repeat>{{}}</template>');
@@ -92,45 +95,72 @@
 
     var template = div.nodes[0];
     recursivelySetTemplateModel(div, model, delegate);
-    performMicrotaskCheckpoint();
+    return new Future(() {
 
-    expect(div.nodes.length, 4);
-    expect(div.nodes[0].tagName, 'TEMPLATE');
-    expect(div.nodes[1].text, 'a');
-    expect(div.nodes[2].text, 'b');
-    expect(div.nodes[3].text, 'c');
+      expect(div.nodes.length, 4);
+      expect(div.nodes[0].tagName, 'TEMPLATE');
+      expect(div.nodes[1].text, 'a');
+      expect(div.nodes[2].text, 'b');
+      expect(div.nodes[3].text, 'c');
 
-    expect(delegate.log, [
-      ['prepare', template],
-      ['bindFn', model[0], 0],
-      ['bindFn', model[1], 1],
-      ['bindFn', model[2], 2],
-    ]);
+      expect(delegate.log, [
+        ['prepare', template],
+        ['bindFn', model[0], 0],
+        ['bindFn', model[1], 1],
+        ['bindFn', model[2], 2],
+      ]);
 
-    delegate.log.clear();
+      delegate.log.clear();
 
-    model.removeAt(1);
-    performMicrotaskCheckpoint();
+      model.removeAt(1);
+    }).then(endOfMicrotask).then((_) {
 
-    expect(delegate.log, [['bindFn', 'c', 1]], reason: 'removed item');
+      expect(delegate.log, [['bindFn', 'c', 1]], reason: 'removed item');
 
-    expect(div.nodes.skip(1).map((n) => n.text), ['a', 'c']);
+      expect(div.nodes.skip(1).map((n) => n.text), ['a', 'c']);
+    });
   });
 
-  observeTest('Basic', () {
+
+  test('Update bindingDelegate with active template', () {
+    var model = toObservable([1, 2]);
+
+    var div = createTestHtml(
+        '<template repeat>{{ \$index }} - {{ \$ident }}</template>');
+    var template = templateBind(div.firstChild)
+      ..bindingDelegate = new UpdateBindingDelegateA()
+      ..model = model;
+
+    return new Future(() {
+      expect(div.nodes.length, 3);
+      expect(div.nodes[1].text, 'i:0 - a:1');
+      expect(div.nodes[2].text, 'i:1 - a:2');
+
+      template.bindingDelegate = new UpdateBindingDelegateB();
+      model.add(3);
+    }).then(nextMicrotask).then((_) {
+      expect(4, div.nodes.length);
+      expect(div.nodes[1].text, 'i:0 - a:1');
+      expect(div.nodes[2].text, 'i:1 - a:2');
+      expect(div.nodes[3].text, 'I:4 - A:3-narg');
+    });
+  });
+
+  test('Basic', () {
     var model = fooModel(2, 4);
     var div = createTestHtml(
         '<template bind>'
         '{{ foo }} + {{ 2x: bar }} + {{ 4x: bar }}</template>');
     recursivelySetTemplateModel(div, model, new TimesTwoSyntax());
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.text, '2 + 8 + ');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, '2 + 8 + ');
 
-    model.foo = 4;
-    model.bar = 8;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.text, '4 + 16 + ');
+      model.foo = 4;
+      model.bar = 8;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.text, '4 + 16 + ');
+    });
   });
 
   // Note: issue-141 test not included here as it's not related to the
@@ -147,9 +177,11 @@
     int id = log.length;
     log.add(['prepare', path, name, tagName]);
     final outerNode = node;
-    return (model, node) {
+    return (model, node, oneTime) {
       var tagName = node is Element ? node.tagName : 'TEXT';
       log.add(['bindFn', model, tagName, id]);
+      return oneTime ? new PropertyPath(path).getValueFrom(model) :
+          new PathObserver(model, path);
     };
   }
 }
@@ -199,8 +231,42 @@
     if (!path.startsWith('2x:')) return null;
 
     path = path.substring(3);
-    return (model, _) {
-      return new PathObserver(model, path, computeValue: (x) => 2 * x);
+    return (model, _, oneTime) {
+      return new ObserverTransform(new PathObserver(model, path), (x) => 2 * x);
     };
   }
 }
+
+class UpdateBindingDelegateBase extends BindingDelegate {
+  bindingHandler(prefix, path) => (model, _, oneTime) =>
+      new ObserverTransform(new PathObserver(model, path), (x) => '$prefix:$x');
+}
+
+class UpdateBindingDelegateA extends UpdateBindingDelegateBase {
+  prepareBinding(path, name, node) {
+    if (path == '\$ident') return bindingHandler('a', 'id');
+    if (path == '\$index') return bindingHandler('i', 'index');
+  }
+
+  prepareInstanceModel(template) => (model) => toObservable({ 'id': model });
+
+  prepareInstancePositionChanged(template) => (templateInstance, index) {
+    templateInstance.model['index'] = index;
+  };
+}
+
+class UpdateBindingDelegateB extends UpdateBindingDelegateBase {
+  prepareBinding(path, name, node) {
+    if (path == '\$ident') return bindingHandler('A', 'id');
+    if (path == '\$index') return bindingHandler('I', 'index');
+  }
+
+  prepareInstanceModel(template) =>
+      (model) => toObservable({ 'id': '${model}-narg' });
+
+
+  prepareInstancePositionChanged(template) => (templateInstance, index) {
+    templateInstance.model['index'] = 2 * index;
+  };
+}
+
diff --git a/pkg/template_binding/test/custom_element_bindings_test.dart b/pkg/template_binding/test/custom_element_bindings_test.dart
index cc12875..d3c22c9 100644
--- a/pkg/template_binding/test/custom_element_bindings_test.dart
+++ b/pkg/template_binding/test/custom_element_bindings_test.dart
@@ -8,14 +8,14 @@
 import 'dart:html';
 import 'package:custom_element/polyfill.dart';
 import 'package:template_binding/template_binding.dart';
-import 'package:observe/observe.dart' show toObservable;
+import 'package:observe/observe.dart';
 import 'package:unittest/html_config.dart';
 import 'package:unittest/unittest.dart';
 import 'utils.dart';
 
 Future _registered;
 
-main() {
+main() => dirtyCheckZone().run(() {
   useHtmlConfiguration();
 
   _registered = loadCustomElementPolyfill().then((_) {
@@ -24,7 +24,7 @@
   });
 
   group('Custom Element Bindings', customElementBindingsTest);
-}
+});
 
 customElementBindingsTest() {
   setUp(() {
@@ -37,13 +37,13 @@
     testDiv = null;
   });
 
-  observeTest('override bind/unbind/unbindAll', () {
+  test('override bind/unbind/unbindAll', () {
     var element = new MyCustomElement();
     var model = toObservable({'a': new Point(123, 444), 'b': new Monster(100)});
 
     nodeBind(element)
-        ..bind('my-point', model, 'a')
-        ..bind('scary-monster', model, 'b');
+        ..bind('my-point', new PathObserver(model, 'a'))
+        ..bind('scary-monster', new PathObserver(model, 'b'));
 
     expect(element.attributes, isNot(contains('my-point')));
     expect(element.attributes, isNot(contains('scary-monster')));
@@ -52,65 +52,67 @@
     expect(element.scaryMonster, model['b']);
 
     model['a'] = null;
-    performMicrotaskCheckpoint();
-    expect(element.myPoint, null);
-    nodeBind(element).unbind('my-point');
+    return new Future(() {
+      expect(element.myPoint, null);
+      nodeBind(element).unbind('my-point');
 
-    model['a'] = new Point(1, 2);
-    model['b'] = new Monster(200);
-    performMicrotaskCheckpoint();
-    expect(element.scaryMonster, model['b']);
-    expect(element.myPoint, null, reason: 'a was unbound');
+      model['a'] = new Point(1, 2);
+      model['b'] = new Monster(200);
+    }).then(endOfMicrotask).then((_) {
+      expect(element.scaryMonster, model['b']);
+      expect(element.myPoint, null, reason: 'a was unbound');
 
-    nodeBind(element).unbindAll();
-    model['b'] = null;
-    performMicrotaskCheckpoint();
-    expect(element.scaryMonster.health, 200);
+      nodeBind(element).unbindAll();
+      model['b'] = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(element.scaryMonster.health, 200);
+    });
   });
 
-  observeTest('override attribute setter', () {
+  test('override attribute setter', () {
     var element = new WithAttrsCustomElement();
     var model = toObservable({'a': 1, 'b': 2});
-    nodeBind(element).bind('hidden?', model, 'a');
-    nodeBind(element).bind('id', model, 'b');
+    nodeBind(element).bind('hidden?', new PathObserver(model, 'a'));
+    nodeBind(element).bind('id', new PathObserver(model, 'b'));
 
     expect(element.attributes, contains('hidden'));
     expect(element.attributes['hidden'], '');
     expect(element.id, '2');
 
     model['a'] = null;
-    performMicrotaskCheckpoint();
-    expect(element.attributes, isNot(contains('hidden')),
-        reason: 'null is false-y');
+    return new Future(() {
+      expect(element.attributes, isNot(contains('hidden')),
+          reason: 'null is false-y');
 
-    model['a'] = false;
-    performMicrotaskCheckpoint();
-    expect(element.attributes, isNot(contains('hidden')));
+      model['a'] = false;
+    }).then(endOfMicrotask).then((_) {
+      expect(element.attributes, isNot(contains('hidden')));
 
-    model['a'] = 'foo';
-    // TODO(jmesserly): this is here to force an ordering between the two
-    // changes. Otherwise the order depends on what order StreamController
-    // chooses to fire the two listeners in.
-    performMicrotaskCheckpoint();
+      model['a'] = 'foo';
+      // TODO(jmesserly): this is here to force an ordering between the two
+      // changes. Otherwise the order depends on what order StreamController
+      // chooses to fire the two listeners in.
+    }).then(endOfMicrotask).then((_) {
 
-    model['b'] = 'x';
-    performMicrotaskCheckpoint();
-    expect(element.attributes, contains('hidden'));
-    expect(element.attributes['hidden'], '');
-    expect(element.id, 'x');
+      model['b'] = 'x';
+    }).then(endOfMicrotask).then((_) {
+      expect(element.attributes, contains('hidden'));
+      expect(element.attributes['hidden'], '');
+      expect(element.id, 'x');
 
-    expect(element.attributes.log, [
-      ['remove', 'hidden?'],
-      ['[]=', 'hidden', ''],
-      ['[]=', 'id', '2'],
-      ['remove', 'hidden'],
-      ['remove', 'hidden'],
-      ['[]=', 'hidden', ''],
-      ['[]=', 'id', 'x'],
-    ]);
+      expect(element.attributes.log, [
+        ['remove', 'hidden?'],
+        ['[]=', 'hidden', ''],
+        ['[]=', 'id', '2'],
+        ['remove', 'hidden'],
+        ['remove', 'hidden'],
+        ['[]=', 'hidden', ''],
+        ['[]=', 'id', 'x'],
+      ]);
+    });
   });
 
-  observeTest('template bind uses overridden custom element bind', () {
+  test('template bind uses overridden custom element bind', () {
 
     var model = toObservable({'a': new Point(123, 444), 'b': new Monster(100)});
     var div = createTestHtml('<template bind>'
@@ -119,34 +121,36 @@
         '</template>');
 
     templateBind(div.query('template')).model = model;
-    performMicrotaskCheckpoint();
+    var element;
+    return new Future(() {
+      print('!!! running future');
+      element = div.nodes[1];
 
-    var element = div.nodes[1];
+      expect(element is MyCustomElement, true,
+          reason: '$element should be a MyCustomElement');
 
-    expect(element is MyCustomElement, true,
-        reason: '$element should be a MyCustomElement');
+      expect(element.myPoint, model['a']);
+      expect(element.scaryMonster, model['b']);
 
-    expect(element.myPoint, model['a']);
-    expect(element.scaryMonster, model['b']);
+      expect(element.attributes, isNot(contains('my-point')));
+      expect(element.attributes, isNot(contains('scary-monster')));
 
-    expect(element.attributes, isNot(contains('my-point')));
-    expect(element.attributes, isNot(contains('scary-monster')));
+      model['a'] = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(element.myPoint, null);
 
-    model['a'] = null;
-    performMicrotaskCheckpoint();
-    expect(element.myPoint, null);
+      templateBind(div.query('template')).model = null;
+    }).then(endOfMicrotask).then((_) {
 
-    templateBind(div.query('template')).model = null;
-    performMicrotaskCheckpoint();
+      expect(element.parentNode, null, reason: 'element was detached');
 
-    expect(element.parentNode, null, reason: 'element was detached');
+      model['a'] = new Point(1, 2);
+      model['b'] = new Monster(200);
+    }).then(endOfMicrotask).then((_) {
 
-    model['a'] = new Point(1, 2);
-    model['b'] = new Monster(200);
-    performMicrotaskCheckpoint();
-
-    expect(element.myPoint, null, reason: 'model was unbound');
-    expect(element.scaryMonster.health, 100, reason: 'model was unbound');
+      expect(element.myPoint, null, reason: 'model was unbound');
+      expect(element.scaryMonster.health, 100, reason: 'model was unbound');
+    });
   });
 
 }
@@ -165,35 +169,30 @@
 
   MyCustomElement.created() : super.created();
 
-  NodeBinding bind(String name, model, [String path]) {
+  Bindable bind(String name, value, {oneTime: false}) {
     switch (name) {
       case 'my-point':
       case 'scary-monster':
         attributes.remove(name);
+        if (oneTime) {
+          _setProperty(name, value);
+          return null;
+        }
         unbind(name);
-        return bindings[name] = new _MyCustomBinding(this, name, model, path);
+        _setProperty(name, value.open((x) => _setProperty(name, x)));
+        return bindings[name] = value;
     }
-    return nodeBindFallback(this).bind(name, model, path);
+    return nodeBindFallback(this).bind(name, value, oneTime: oneTime);
   }
 
   unbind(name) => nodeBindFallback(this).unbind(name);
   unbindAll() => nodeBindFallback(this).unbindAll();
   get bindings => nodeBindFallback(this).bindings;
   get templateInstance => nodeBindFallback(this).templateInstance;
-}
 
-class _MyCustomBinding extends NodeBinding {
-  _MyCustomBinding(MyCustomElement node, property, model, path)
-      : super(node, property, model, path) {
-
-    node.attributes.remove(property);
-  }
-
-  MyCustomElement get node => super.node;
-
-  void valueChanged(newValue) {
-    if (property == 'my-point') node.myPoint = newValue;
-    if (property == 'scary-monster') node.scaryMonster = newValue;
+  void _setProperty(String property, newValue) {
+    if (property == 'my-point') myPoint = newValue;
+    if (property == 'scary-monster') scaryMonster = newValue;
   }
 }
 
diff --git a/pkg/template_binding/test/node_bind_test.dart b/pkg/template_binding/test/node_bind_test.dart
index fbedcfa..93bcd8f 100644
--- a/pkg/template_binding/test/node_bind_test.dart
+++ b/pkg/template_binding/test/node_bind_test.dart
@@ -4,11 +4,12 @@
 
 library template_binding.test.node_bind_test;
 
+import 'dart:async';
 import 'dart:html';
 
-import 'package:observe/observe.dart' show toObservable, PathObserver;
+import 'package:observe/observe.dart'
+    show toObservable, PathObserver, PropertyPath;
 import 'package:template_binding/template_binding.dart' show nodeBind;
-import 'package:template_binding/src/node_binding.dart' show getObserverForTest;
 
 import 'package:unittest/html_config.dart';
 import 'package:unittest/unittest.dart';
@@ -17,7 +18,7 @@
 // Note: this file ported from
 // https://github.com/toolkitchen/mdv/blob/master/tests/node_bindings.js
 
-main() {
+main() => dirtyCheckZone().run(() {
   useHtmlConfiguration();
 
   setUp(() {
@@ -29,147 +30,162 @@
     testDiv = null;
   });
 
-
   group('Text bindings', testBindings);
   group('Element attribute bindings', elementBindings);
   group('Form Element bindings', formBindings);
-}
+});
 
 testBindings() {
-  observeTest('Basic', () {
+  test('Basic', () {
     var text = new Text('hi');
     var model = toObservable({'a': 1});
-    nodeBind(text).bind('text', model, 'a');
+    nodeBind(text).bind('text', new PathObserver(model, 'a'));
     expect(text.text, '1');
 
     model['a'] = 2;
-    performMicrotaskCheckpoint();
-    expect(text.text, '2');
+    return new Future(() {
+      expect(text.text, '2');
 
-    nodeBind(text).unbind('text');
-    model['a'] = 3;
-    performMicrotaskCheckpoint();
-    expect(text.text, '2');
-
-    // TODO(rafaelw): Throw on binding to unavailable property?
+      nodeBind(text).unbind('text');
+      model['a'] = 3;
+    }).then(endOfMicrotask).then((_) {
+      // TODO(rafaelw): Throw on binding to unavailable property?
+      expect(text.text, '2');
+    });
   });
 
-  observeTest('No Path', () {
+  test('oneTime', () {
     var text = new Text('hi');
-    var model = 1;
-    nodeBind(text).bind('text', model);
+    nodeBind(text).bind('text', 1, oneTime: true);
     expect(text.text, '1');
   });
 
-  observeTest('Path unreachable', () {
+  test('No Path', () {
+    var text = new Text('hi');
+    var model = 1;
+    nodeBind(text).bind('text', new PathObserver(model));
+    expect(text.text, '1');
+  });
+
+  test('Path unreachable', () {
     var text = testDiv.append(new Text('hi'));
     var model = 1;
-    nodeBind(text).bind('text', model, 'a');
+    nodeBind(text).bind('text', new PathObserver(model, 'a'));
     expect(text.text, '');
   });
 
-  observeTest('Observer is Model', () {
+  test('Observer is Model', () {
     var text = new Text('');
     var model = toObservable({'a': {'b': {'c': 1}}});
     var observer = new PathObserver(model, 'a.b.c');
-    nodeBind(text).bind('text', observer, 'value');
+    nodeBind(text).bind('text', observer);
     expect(text.text, '1');
 
     var binding = nodeBind(text).bindings['text'];
-    expect(binding, isNotNull);
-    expect(getObserverForTest(binding), observer,
-        reason: 'should reuse observer');
+    expect(binding, observer, reason: 'should reuse observer');
 
     model['a']['b']['c'] = 2;
-    performMicrotaskCheckpoint();
-    expect(text.text, '2');
-    nodeBind(text).unbind('text');
+    return new Future(() {
+      expect(text.text, '2');
+      nodeBind(text).unbind('text');
+    });
   });
 }
 
 elementBindings() {
-  observeTest('Basic', () {
+  test('Basic', () {
     var el = new DivElement();
     var model = toObservable({'a': '1'});
-    nodeBind(el).bind('foo', model, 'a');
-    performMicrotaskCheckpoint();
-    expect(el.attributes['foo'], '1');
+    nodeBind(el).bind('foo', new PathObserver(model, 'a'));
 
-    model['a'] = '2';
-    performMicrotaskCheckpoint();
-    expect(el.attributes['foo'], '2');
-
-    model['a'] = 232.2;
-    performMicrotaskCheckpoint();
-    expect(el.attributes['foo'], '232.2');
-
-    model['a'] = 232;
-    performMicrotaskCheckpoint();
-    expect(el.attributes['foo'], '232');
-
-    model['a'] = null;
-    performMicrotaskCheckpoint();
-    expect(el.attributes['foo'], '');
+    return new Future(() {
+      expect(el.attributes['foo'], '1');
+      model['a'] = '2';
+    }).then(endOfMicrotask).then((_) {
+      expect(el.attributes['foo'], '2');
+      model['a'] = 232.2;
+    }).then(endOfMicrotask).then((_) {
+      expect(el.attributes['foo'], '232.2');
+      model['a'] = 232;
+    }).then(endOfMicrotask).then((_) {
+      expect(el.attributes['foo'], '232');
+      model['a'] = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(el.attributes['foo'], '');
+    });
   });
 
-  observeTest('No Path', () {
-    var el = testDiv.append(new DivElement());
-    var model = 1;
-    nodeBind(el).bind('foo', model);
-    expect(el.attributes['foo'], '1');
-  });
-
-  observeTest('Path unreachable', () {
-    var el = testDiv.append(new DivElement());
-    var model = toObservable({});
-    nodeBind(el).bind('foo', model, 'bar');
-    expect(el.attributes['foo'], '');
-  });
-
-  observeTest('Dashes', () {
+  test('oneTime', () {
     var el = testDiv.append(new DivElement());
     var model = toObservable({'a': '1'});
-    nodeBind(el).bind('foo-bar', model, 'a');
-    performMicrotaskCheckpoint();
-    expect(el.attributes['foo-bar'], '1');
-
-    model['a'] = '2';
-    performMicrotaskCheckpoint();
-    expect(el.attributes['foo-bar'], '2');
+    nodeBind(el).bind('foo', 1, oneTime: true);
+    expect('1', el.attributes['foo']);
   });
 
-  observeTest('Element.id, Element.hidden?', () {
+  test('No Path', () {
+    var el = testDiv.append(new DivElement());
+    var model = 1;
+    nodeBind(el).bind('foo', new PathObserver(model));
+    return new Future(() {
+      expect(el.attributes['foo'], '1');
+    });
+  });
+
+  test('Path unreachable', () {
+    var el = testDiv.append(new DivElement());
+    var model = toObservable({});
+    nodeBind(el).bind('foo', new PathObserver(model, 'bar'));
+    return new Future(() {
+      expect(el.attributes['foo'], '');
+    });
+  });
+
+  test('Dashes', () {
+    var el = testDiv.append(new DivElement());
+    var model = toObservable({'a': '1'});
+    nodeBind(el).bind('foo-bar', new PathObserver(model, 'a'));
+    return new Future(() {
+      expect(el.attributes['foo-bar'], '1');
+      model['a'] = '2';
+
+    }).then(endOfMicrotask).then((_) {
+      expect(el.attributes['foo-bar'], '2');
+    });
+  });
+
+  test('Element.id, Element.hidden?', () {
     var element = new DivElement();
     var model = toObservable({'a': 1, 'b': 2});
-    nodeBind(element).bind('hidden?', model, 'a');
-    nodeBind(element).bind('id', model, 'b');
+    nodeBind(element).bind('hidden?', new PathObserver(model, 'a'));
+    nodeBind(element).bind('id', new PathObserver(model, 'b'));
 
     expect(element.attributes, contains('hidden'));
     expect(element.attributes['hidden'], '');
     expect(element.id, '2');
 
     model['a'] = null;
-    performMicrotaskCheckpoint();
-    expect(element.attributes, isNot(contains('hidden')),
-        reason: 'null is false-y');
+    return new Future(() {
+      expect(element.attributes, isNot(contains('hidden')),
+          reason: 'null is false-y');
 
-    model['a'] = false;
-    performMicrotaskCheckpoint();
-    expect(element.attributes, isNot(contains('hidden')));
+      model['a'] = false;
+    }).then(endOfMicrotask).then((_) {
+      expect(element.attributes, isNot(contains('hidden')));
 
-    model['a'] = 'foo';
-    model['b'] = 'x';
-    performMicrotaskCheckpoint();
-    expect(element.attributes, contains('hidden'));
-    expect(element.attributes['hidden'], '');
-    expect(element.id, 'x');
+      model['a'] = 'foo';
+      model['b'] = 'x';
+    }).then(endOfMicrotask).then((_) {
+      expect(element.attributes, contains('hidden'));
+      expect(element.attributes['hidden'], '');
+      expect(element.id, 'x');
+    });
   });
 
-  observeTest('Element.id - path unreachable', () {
+  test('Element.id - path unreachable', () {
     var element = testDiv.append(new DivElement());
     var model = toObservable({});
-    nodeBind(element).bind('id', model, 'a');
-    expect(element.id, '');
+    nodeBind(element).bind('id', new PathObserver(model, 'a'));
+    return new Future(() => expect(element.id, ''));
   });
 }
 
@@ -178,237 +194,284 @@
     var el = new Element.tag(tagName);
     testDiv.nodes.add(el);
     var model = toObservable({'x': 42});
-    nodeBind(el).bind('value', model, 'x');
+    nodeBind(el).bind('value', new PathObserver(model, 'x'));
     expect(el.value, '42');
 
     model['x'] = 'Hi';
     expect(el.value, '42', reason: 'changes delivered async');
-    performMicrotaskCheckpoint();
-    expect(el.value, 'Hi');
+    return new Future(() {
+      expect(el.value, 'Hi');
 
-    el.value = 'changed';
-    dispatchEvent('input', el);
-    expect(model['x'], 'changed');
+      el.value = 'changed';
+      dispatchEvent('input', el);
+      expect(model['x'], 'changed');
 
-    nodeBind(el).unbind('value');
+      nodeBind(el).unbind('value');
 
-    el.value = 'changed again';
-    dispatchEvent('input', el);
-    expect(model['x'], 'changed');
+      el.value = 'changed again';
+      dispatchEvent('input', el);
+      expect(model['x'], 'changed');
 
-    nodeBind(el).bind('value', model, 'x');
-    model['x'] = null;
-    performMicrotaskCheckpoint();
-    expect(el.value, '');
+      nodeBind(el).bind('value', new PathObserver(model, 'x'));
+      model['x'] = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(el.value, '');
+    });
+  }
+
+  inputTextAreaValueOnetime(String tagName) {
+    var el = testDiv.append(new Element.tag(tagName));
+    nodeBind(el).bind('value', 42, oneTime: true);
+    expect(el.value, '42');
   }
 
   inputTextAreaNoPath(String tagName) {
     var el = testDiv.append(new Element.tag(tagName));
     var model = 42;
-    nodeBind(el).bind('value', model);
+    nodeBind(el).bind('value', new PathObserver(model));
     expect(el.value, '42');
   }
 
   inputTextAreaPathUnreachable(String tagName) {
     var el = testDiv.append(new Element.tag(tagName));
     var model = toObservable({});
-    nodeBind(el).bind('value', model, 'a');
+    nodeBind(el).bind('value', new PathObserver(model, 'a'));
     expect(el.value, '');
   }
 
-  observeTest('Input.value',
+  test('Input.value',
       () => inputTextAreaValueTest('input'));
-  observeTest('Input.value - no path',
+
+  test('Input.value - oneTime',
+      () => inputTextAreaValueOnetime('input'));
+
+  test('Input.value - no path',
       () => inputTextAreaNoPath('input'));
-  observeTest('Input.value - path unreachable',
+
+  test('Input.value - path unreachable',
       () => inputTextAreaPathUnreachable('input'));
-  observeTest('TextArea.value',
+
+  test('TextArea.value',
       () => inputTextAreaValueTest('textarea'));
-  observeTest('TextArea.value - no path',
+
+  test('TextArea.value - oneTime',
+      () => inputTextAreaValueOnetime('textarea'));
+
+  test('TextArea.value - no path',
       () => inputTextAreaNoPath('textarea'));
-  observeTest('TextArea.value - path unreachable',
+
+  test('TextArea.value - path unreachable',
       () => inputTextAreaPathUnreachable('textarea'));
 
-  observeTest('Radio Input', () {
+  test('Radio Input', () {
     var input = new InputElement();
     input.type = 'radio';
     var model = toObservable({'x': true});
-    nodeBind(input).bind('checked', model, 'x');
+    nodeBind(input).bind('checked', new PathObserver(model, 'x'));
     expect(input.checked, true);
 
     model['x'] = false;
     expect(input.checked, true);
-    performMicrotaskCheckpoint();
-    expect(input.checked, false,reason: 'model change should update checked');
+    return new Future(() {
+      expect(input.checked, false,reason: 'model change should update checked');
 
-    input.checked = true;
-    dispatchEvent('change', input);
-    expect(model['x'], true, reason: 'input.checked should set model');
+      input.checked = true;
+      dispatchEvent('change', input);
+      expect(model['x'], true, reason: 'input.checked should set model');
 
-    nodeBind(input).unbind('checked');
+      nodeBind(input).unbind('checked');
 
-    input.checked = false;
-    dispatchEvent('change', input);
-    expect(model['x'], true,
-        reason: 'disconnected binding should not fire');
+      input.checked = false;
+      dispatchEvent('change', input);
+      expect(model['x'], true,
+          reason: 'disconnected binding should not fire');
+    });
   });
 
-  observeTest('Input.value - user value rejected', () {
+  test('Input.value - user value rejected', () {
     var model = toObservable({'val': 'ping'});
 
     var el = new InputElement();
-    nodeBind(el).bind('value', model, 'val');
-    performMicrotaskCheckpoint();
-    expect(el.value, 'ping');
+    nodeBind(el).bind('value', new PathObserver(model, 'val'));
+    return new Future(() {
+      expect(el.value, 'ping');
 
-    el.value = 'pong';
-    dispatchEvent('input', el);
-    expect(model['val'], 'pong');
+      el.value = 'pong';
+      dispatchEvent('input', el);
+      expect(model['val'], 'pong');
 
-    // Try a deep path.
-    model = toObservable({'a': {'b': {'c': 'ping'}}});
+      // Try a deep path.
+      model = toObservable({'a': {'b': {'c': 'ping'}}});
 
-    nodeBind(el).bind('value', model, 'a.b.c');
-    performMicrotaskCheckpoint();
-    expect(el.value, 'ping');
+      nodeBind(el).bind('value', new PathObserver(model, 'a.b.c'));
+    }).then(endOfMicrotask).then((_) {
+      expect(el.value, 'ping');
 
-    el.value = 'pong';
-    dispatchEvent('input', el);
-    expect(new PathObserver(model, 'a.b.c').value, 'pong');
+      el.value = 'pong';
+      dispatchEvent('input', el);
+      expect(new PropertyPath('a.b.c').getValueFrom(model), 'pong');
 
-    // Start with the model property being absent.
-    model['a']['b'].remove('c');
-    performMicrotaskCheckpoint();
-    expect(el.value, '');
+      // Start with the model property being absent.
+      model['a']['b'].remove('c');
+    }).then(endOfMicrotask).then((_) {
+      expect(el.value, '');
 
-    el.value = 'pong';
-    dispatchEvent('input', el);
-    expect(new PathObserver(model, 'a.b.c').value, 'pong');
-    performMicrotaskCheckpoint();
+      el.value = 'pong';
+      dispatchEvent('input', el);
+      expect(new PropertyPath('a.b.c').getValueFrom(model), 'pong');
+    }).then(endOfMicrotask).then((_) {
 
-    // Model property unreachable (and unsettable).
-    model['a'].remove('b');
-    performMicrotaskCheckpoint();
-    expect(el.value, '');
+      // Model property unreachable (and unsettable).
+      model['a'].remove('b');
+    }).then(endOfMicrotask).then((_) {
+      expect(el.value, '');
 
-    el.value = 'pong';
-    dispatchEvent('input', el);
-    expect(new PathObserver(model, 'a.b.c').value, null);
+      el.value = 'pong';
+      dispatchEvent('input', el);
+      expect(new PropertyPath('a.b.c').getValueFrom(model), null);
+    });
   });
 
-  observeTest('(Checkbox)Input.checked', () {
+  test('Checkbox Input.checked', () {
     var el = testDiv.append(new InputElement());
     el.type = 'checkbox';
 
     var model = toObservable({'x': true});
-    nodeBind(el).bind('checked', model, 'x');
+    nodeBind(el).bind('checked', new PathObserver(model, 'x'));
     expect(el.checked, true);
 
     model['x'] = false;
     expect(el.checked, true, reason: 'changes delivered async');
-    performMicrotaskCheckpoint();
-    expect(el.checked, false);
+    return new Future(() {
+      expect(el.checked, false);
 
-    el.click();
-    expect(model['x'], true);
-    performMicrotaskCheckpoint();
+      el.click();
+      expect(model['x'], true);
+    }).then(endOfMicrotask).then((_) {
 
-    el.click();
-    expect(model['x'], false);
+      el.click();
+      expect(model['x'], false);
+    });
   });
 
-  observeTest('(Checkbox)Input.checked - path unreachable', () {
+  test('Checkbox Input.checked - oneTime', () {
+    var input = testDiv.append(new InputElement());
+    input.type = 'checkbox';
+    nodeBind(input).bind('checked', true, oneTime: true);
+    expect(input.checked, true, reason: 'checked was set');
+  });
+
+  test('Checkbox Input.checked - path unreachable', () {
     var input = testDiv.append(new InputElement());
     input.type = 'checkbox';
     var model = toObservable({});
-    nodeBind(input).bind('checked', model, 'x');
+    nodeBind(input).bind('checked', new PathObserver(model, 'x'));
     expect(input.checked, false);
   });
 
-  observeTest('(Checkbox)Input.checked 2', () {
+  test('Checkbox Input.checked 2', () {
     var model = toObservable({'val': true});
 
     var el = testDiv.append(new InputElement());
     el.type = 'checkbox';
-    nodeBind(el).bind('checked', model, 'val');
-    performMicrotaskCheckpoint();
-    expect(el.checked, true);
+    nodeBind(el).bind('checked', new PathObserver(model, 'val'));
+    return new Future(() {
+      expect(el.checked, true);
 
-    model['val'] = false;
-    performMicrotaskCheckpoint();
-    expect(el.checked, false);
+      model['val'] = false;
+    }).then(endOfMicrotask).then((_) {
+      expect(el.checked, false);
 
-    el.click();
-    expect(model['val'], true);
-
-    el.click();
-    expect(model['val'], false);
-
-    el.onClick.listen((_) {
+      el.click();
       expect(model['val'], true);
-    });
-    el.onChange.listen((_) {
-      expect(model['val'], true);
-    });
 
-    el.dispatchEvent(new MouseEvent('click', view: window));
+      el.click();
+      expect(model['val'], false);
+
+      el.onClick.listen((_) {
+        expect(model['val'], true);
+      });
+      el.onChange.listen((_) {
+        expect(model['val'], true);
+      });
+
+      el.dispatchEvent(new MouseEvent('click', view: window));
+    });
   });
 
-  observeTest('(Checkbox)Input.checked - binding updated on click', () {
+  test('Checkbox Input.checked - binding updated on click', () {
     var model = toObservable({'val': true});
 
     var el = new InputElement();
     testDiv.append(el);
     el.type = 'checkbox';
-    nodeBind(el).bind('checked', model, 'val');
-    performMicrotaskCheckpoint();
-    expect(el.checked, true);
+    nodeBind(el).bind('checked', new PathObserver(model, 'val'));
+    return new Future(() {
+      expect(el.checked, true);
 
-    el.onClick.listen((_) {
-      expect(model['val'], false);
+      int fired = 0;
+      el.onClick.listen((_) {
+        fired++;
+        expect(model['val'], false);
+      });
+
+      el.dispatchEvent(new MouseEvent('click', view: window));
+
+      expect(fired, 1, reason: 'events dispatched synchronously');
     });
-
-    el.dispatchEvent(new MouseEvent('click', view: window));
   });
 
-  observeTest('(Checkbox)Input.checked - binding updated on change', () {
+  test('Checkbox Input.checked - binding updated on change', () {
     var model = toObservable({'val': true});
 
     var el = new InputElement();
     testDiv.append(el);
     el.type = 'checkbox';
-    nodeBind(el).bind('checked', model, 'val');
-    performMicrotaskCheckpoint();
-    expect(el.checked, true);
+    nodeBind(el).bind('checked', new PathObserver(model, 'val'));
+    return new Future(() {
+      expect(el.checked, true);
 
-    el.onChange.listen((_) {
-      expect(model['val'], false);
+      int fired = 0;
+      el.onChange.listen((_) {
+        fired++;
+        expect(model['val'], false);
+      });
+
+      el.dispatchEvent(new MouseEvent('click', view: window));
+
+      expect(fired, 1, reason: 'events dispatched synchronously');
     });
-
-    el.dispatchEvent(new MouseEvent('click', view: window));
   });
 
-  observeTest('(Radio)Input.checked', () {
+  test('Radio Input.checked', () {
     var input = testDiv.append(new InputElement());
     input.type = 'radio';
     var model = toObservable({'x': true});
-    nodeBind(input).bind('checked', model, 'x');
+    nodeBind(input).bind('checked', new PathObserver(model, 'x'));
     expect(input.checked, true);
 
     model['x'] = false;
     expect(input.checked, true);
-    performMicrotaskCheckpoint();
-    expect(input.checked, false);
+    return new Future(() {
+      expect(input.checked, false);
 
-    input.checked = true;
-    dispatchEvent('change', input);
-    expect(model['x'], true);
+      input.checked = true;
+      dispatchEvent('change', input);
+      expect(model['x'], true);
 
-    nodeBind(input).unbind('checked');
+      nodeBind(input).unbind('checked');
 
-    input.checked = false;
-    dispatchEvent('change', input);
-    expect(model['x'], true);
+      input.checked = false;
+      dispatchEvent('change', input);
+      expect(model['x'], true);
+    });
+  });
+
+  test('Radio Input.checked - oneTime', () {
+    var input = testDiv.append(new InputElement());
+    input.type = 'radio';
+    nodeBind(input).bind('checked', true, oneTime: true);
+    expect(input.checked, true, reason: 'checked was set');
   });
 
   radioInputChecked2(host) {
@@ -421,69 +484,67 @@
     var el1 = container.append(new InputElement());
     el1.type = 'radio';
     el1.name = RADIO_GROUP_NAME;
-    nodeBind(el1).bind('checked', model, 'val1');
+    nodeBind(el1).bind('checked', new PathObserver(model, 'val1'));
 
     var el2 = container.append(new InputElement());
     el2.type = 'radio';
     el2.name = RADIO_GROUP_NAME;
-    nodeBind(el2).bind('checked', model, 'val2');
+    nodeBind(el2).bind('checked', new PathObserver(model, 'val2'));
 
     var el3 = container.append(new InputElement());
     el3.type = 'radio';
     el3.name = RADIO_GROUP_NAME;
-    nodeBind(el3).bind('checked', model, 'val3');
+    nodeBind(el3).bind('checked', new PathObserver(model, 'val3'));
 
     var el4 = container.append(new InputElement());
     el4.type = 'radio';
     el4.name = 'othergroup';
-    nodeBind(el4).bind('checked', model, 'val4');
+    nodeBind(el4).bind('checked', new PathObserver(model, 'val4'));
 
-    performMicrotaskCheckpoint();
-    expect(el1.checked, true);
-    expect(el2.checked, false);
-    expect(el3.checked, false);
-    expect(el4.checked, true);
+    return new Future(() {
+      expect(el1.checked, true);
+      expect(el2.checked, false);
+      expect(el3.checked, false);
+      expect(el4.checked, true);
 
-    model['val1'] = false;
-    model['val2'] = true;
-    performMicrotaskCheckpoint();
-    expect(el1.checked, false);
-    expect(el2.checked, true);
-    expect(el3.checked, false);
-    expect(el4.checked, true);
+      model['val1'] = false;
+      model['val2'] = true;
+    }).then(endOfMicrotask).then((_) {
+      expect(el1.checked, false);
+      expect(el2.checked, true);
+      expect(el3.checked, false);
+      expect(el4.checked, true);
 
-    el1.checked = true;
-    dispatchEvent('change', el1);
-    expect(model['val1'], true);
-    expect(model['val2'], false);
-    expect(model['val3'], false);
-    expect(model['val4'], true);
+      el1.checked = true;
+      dispatchEvent('change', el1);
+      expect(model['val1'], true);
+      expect(model['val2'], false);
+      expect(model['val3'], false);
+      expect(model['val4'], true);
 
-    el3.checked = true;
-    dispatchEvent('change', el3);
-    expect(model['val1'], false);
-    expect(model['val2'], false);
-    expect(model['val3'], true);
-    expect(model['val4'], true);
+      el3.checked = true;
+      dispatchEvent('change', el3);
+      expect(model['val1'], false);
+      expect(model['val2'], false);
+      expect(model['val3'], true);
+      expect(model['val4'], true);
+    });
   }
 
-  observeTest('(Radio)Input.checked 2', () {
-    radioInputChecked2(testDiv);
-  });
+  test('Radio Input.checked 2', () => radioInputChecked2(testDiv));
 
-  observeTest('(Radio)Input.checked 2 - ShadowRoot', () {
-    if (!ShadowRoot.supported) return;
+  test('Radio Input.checked 2 - ShadowRoot', () {
+    if (!ShadowRoot.supported) return null;
 
-    var div = new DivElement();
-    var shadowRoot = div.createShadowRoot();
-    radioInputChecked2(shadowRoot);
-    unbindAll(shadowRoot);
+    var shadowRoot = new DivElement().createShadowRoot();
+    return radioInputChecked2(shadowRoot)
+        .whenComplete(() => unbindAll(shadowRoot));
   });
 
   radioInputCheckedMultipleForms(host) {
     var model = toObservable({'val1': true, 'val2': false, 'val3': false,
         'val4': true});
-    var RADIO_GROUP_NAME = 'observeTest';
+    var RADIO_GROUP_NAME = 'test';
 
     var container = testDiv.append(new DivElement());
     var form1 = new FormElement();
@@ -495,64 +556,65 @@
     form1.append(el1);
     el1.type = 'radio';
     el1.name = RADIO_GROUP_NAME;
-    nodeBind(el1).bind('checked', model, 'val1');
+    nodeBind(el1).bind('checked', new PathObserver(model, 'val1'));
 
     var el2 = new InputElement();
     form1.append(el2);
     el2.type = 'radio';
     el2.name = RADIO_GROUP_NAME;
-    nodeBind(el2).bind('checked', model, 'val2');
+    nodeBind(el2).bind('checked', new PathObserver(model, 'val2'));
 
     var el3 = new InputElement();
     form2.append(el3);
     el3.type = 'radio';
     el3.name = RADIO_GROUP_NAME;
-    nodeBind(el3).bind('checked', model, 'val3');
+    nodeBind(el3).bind('checked', new PathObserver(model, 'val3'));
 
     var el4 = new InputElement();
     form2.append(el4);
     el4.type = 'radio';
     el4.name = RADIO_GROUP_NAME;
-    nodeBind(el4).bind('checked', model, 'val4');
+    nodeBind(el4).bind('checked', new PathObserver(model, 'val4'));
 
-    performMicrotaskCheckpoint();
-    expect(el1.checked, true);
-    expect(el2.checked, false);
-    expect(el3.checked, false);
-    expect(el4.checked, true);
+    return new Future(() {
+      expect(el1.checked, true);
+      expect(el2.checked, false);
+      expect(el3.checked, false);
+      expect(el4.checked, true);
 
-    el2.checked = true;
-    dispatchEvent('change', el2);
-    expect(model['val1'], false);
-    expect(model['val2'], true);
+      el2.checked = true;
+      dispatchEvent('change', el2);
+      expect(model['val1'], false);
+      expect(model['val2'], true);
 
-    // Radio buttons in form2 should be unaffected
-    expect(model['val3'], false);
-    expect(model['val4'], true);
+      // Radio buttons in form2 should be unaffected
+      expect(model['val3'], false);
+      expect(model['val4'], true);
 
-    el3.checked = true;
-    dispatchEvent('change', el3);
-    expect(model['val3'], true);
-    expect(model['val4'], false);
+      el3.checked = true;
+      dispatchEvent('change', el3);
+      expect(model['val3'], true);
+      expect(model['val4'], false);
 
-    // Radio buttons in form1 should be unaffected
-    expect(model['val1'], false);
-    expect(model['val2'], true);
+      // Radio buttons in form1 should be unaffected
+      expect(model['val1'], false);
+      expect(model['val2'], true);
+    });
   }
 
-  observeTest('(Radio)Input.checked - multiple forms', () {
-    radioInputCheckedMultipleForms(testDiv);
+  test('Radio Input.checked - multiple forms', () {
+    return radioInputCheckedMultipleForms(testDiv);
   });
 
-  observeTest('(Radio)Input.checked 2 - ShadowRoot', () {
-    if (!ShadowRoot.supported) return;
+  test('Radio Input.checked - multiple forms - ShadowRoot', () {
+    if (!ShadowRoot.supported) return null;
 
     var shadowRoot = new DivElement().createShadowRoot();
-    radioInputChecked2(shadowRoot);
-    unbindAll(shadowRoot);
+    return radioInputCheckedMultipleForms(shadowRoot)
+        .whenComplete(() => unbindAll(shadowRoot));
   });
 
-  observeTest('Select.selectedIndex', () {
+  test('Select.selectedIndex', () {
     var select = new SelectElement();
     testDiv.append(select);
     var option0 = select.append(new OptionElement());
@@ -561,16 +623,28 @@
 
     var model = toObservable({'val': 2});
 
-    nodeBind(select).bind('selectedIndex', model, 'val');
-    performMicrotaskCheckpoint();
-    expect(select.selectedIndex, 2);
+    nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val'));
+    return new Future(() {
+      expect(select.selectedIndex, 2);
 
-    select.selectedIndex = 1;
-    dispatchEvent('change', select);
-    expect(model['val'], 1);
+      select.selectedIndex = 1;
+      dispatchEvent('change', select);
+      expect(model['val'], 1);
+    });
   });
 
-  observeTest('Select.selectedIndex - path NaN', () {
+  test('Select.selectedIndex - oneTime', () {
+    var select = new SelectElement();
+    testDiv.append(select);
+    var option0 = select.append(new OptionElement());
+    var option1 = select.append(new OptionElement());
+    var option2 = select.append(new OptionElement());
+
+    nodeBind(select).bind('selectedIndex', 2, oneTime: true);
+    return new Future(() => expect(select.selectedIndex, 2));
+  });
+
+  test('Select.selectedIndex - invalid path', () {
     var select = new SelectElement();
     testDiv.append(select);
     var option0 = select.append(new OptionElement());
@@ -580,12 +654,11 @@
 
     var model = toObservable({'val': 'foo'});
 
-    nodeBind(select).bind('selectedIndex', model, 'val');
-    performMicrotaskCheckpoint();
-    expect(select.selectedIndex, 0);
+    nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val'));
+    return new Future(() => expect(select.selectedIndex, 0));
   });
 
-  observeTest('Select.selectedIndex - path unreachable', () {
+  test('Select.selectedIndex - path unreachable', () {
     var select = new SelectElement();
     testDiv.append(select);
     var option0 = select.append(new OptionElement());
@@ -595,24 +668,28 @@
 
     var model = toObservable({});
 
-    nodeBind(select).bind('selectedIndex', model, 'val');
-    performMicrotaskCheckpoint();
-    expect(select.selectedIndex, 0);
+    nodeBind(select).bind('selectedIndex', new PathObserver(model, 'val'));
+    return new Future(() => expect(select.selectedIndex, 0));
   });
 
-  observeTest('Option.value', () {
+  test('Option.value', () {
     var option = testDiv.append(new OptionElement());
     var model = toObservable({'x': 42});
-    nodeBind(option).bind('value', model, 'x');
+    nodeBind(option).bind('value', new PathObserver(model, 'x'));
     expect(option.value, '42');
 
     model['x'] = 'Hi';
     expect(option.value, '42');
-    performMicrotaskCheckpoint();
-    expect(option.value, 'Hi');
+    return new Future(() => expect(option.value, 'Hi'));
   });
 
-  observeTest('Select.value', () {
+  test('Option.value - oneTime', () {
+    var option = testDiv.append(new OptionElement());
+    nodeBind(option).bind('value', 42, oneTime: true);
+    expect(option.value, '42');
+  });
+
+  test('Select.value', () {
     var select = testDiv.append(new SelectElement());
     testDiv.append(select);
     var option0 = select.append(new OptionElement());
@@ -626,25 +703,26 @@
       'selected': 'b'
     });
 
-    nodeBind(option0).bind('value', model, 'opt0');
-    nodeBind(option1).bind('value', model, 'opt1');
-    nodeBind(option2).bind('value', model, 'opt2');
+    nodeBind(option0).bind('value', new PathObserver(model, 'opt0'));
+    nodeBind(option1).bind('value', new PathObserver(model, 'opt1'));
+    nodeBind(option2).bind('value', new PathObserver(model, 'opt2'));
 
-    nodeBind(select).bind('value', model, 'selected');
-    performMicrotaskCheckpoint();
-    expect(select.value, 'b');
+    nodeBind(select).bind('value', new PathObserver(model, 'selected'));
+    return new Future(() {
+      expect(select.value, 'b');
 
-    select.value = 'c';
-    dispatchEvent('change', select);
-    expect(model['selected'], 'c');
+      select.value = 'c';
+      dispatchEvent('change', select);
+      expect(model['selected'], 'c');
 
-    model['opt2'] = 'X';
-    performMicrotaskCheckpoint();
-    expect(select.value, 'X');
-    expect(model['selected'], 'X');
+      model['opt2'] = 'X';
+    }).then(endOfMicrotask).then((_) {
+      expect(select.value, 'X');
+      expect(model['selected'], 'X');
 
-    model['selected'] = 'a';
-    performMicrotaskCheckpoint();
-    expect(select.value, 'a');
+      model['selected'] = 'a';
+    }).then(endOfMicrotask).then((_) {
+      expect(select.value, 'a');
+    });
   });
 }
diff --git a/pkg/template_binding/test/template_binding_test.dart b/pkg/template_binding/test/template_binding_test.dart
index 7639d76..c2ac5a9 100644
--- a/pkg/template_binding/test/template_binding_test.dart
+++ b/pkg/template_binding/test/template_binding_test.dart
@@ -5,7 +5,6 @@
 library template_binding.test.template_binding_test;
 
 import 'dart:async';
-import 'dart:collection';
 import 'dart:html';
 import 'dart:math' as math;
 import 'package:observe/observe.dart';
@@ -18,13 +17,13 @@
 import 'utils.dart';
 
 // Note: this file ported from
-// https://github.com/Polymer/TemplateBinding/blob/ed3266266e751b5ab1f75f8e0509d0d5f0ef35d8/tests/tests.js
+// https://github.com/Polymer/TemplateBinding/blob/fcb7a502794f19544f2d4b77c96eebb70830591d/tests/tests.js
 
 // TODO(jmesserly): submit a small cleanup patch to original. I fixed some
 // cases where "div" and "t" were unintentionally using the JS global scope;
 // look for "assertNodesAre".
 
-main() {
+main() => dirtyCheckZone().run(() {
   useHtmlConfiguration();
 
   // Load MutationObserver polyfill in case IE needs it.
@@ -46,7 +45,7 @@
     expect(MutationObserver.supported, true, reason: 'polyfill was loaded.');
   });
 
-  group('Template Instantiation', templateInstantiationTests);
+  group('Template', templateInstantiationTests);
 
   group('Binding Delegate API', () {
     group('with Observable', () {
@@ -59,7 +58,7 @@
   });
 
   group('Compat', compatTests);
-}
+});
 
 var expando = new Expando('test');
 void addExpandos(node) {
@@ -78,237 +77,710 @@
 }
 
 templateInstantiationTests() {
+  // Dart note: renamed some of these tests to have unique names
 
-  observeTest('Template', () {
+  test('Bind (simple)', () {
     var div = createTestHtml('<template bind={{}}>text</template>');
     templateBind(div.firstChild).model = {};
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.text, 'text');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'text');
 
-    templateBind(div.firstChild).model = null;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+      // Dart note: null is used instead of undefined to clear the template.
+      templateBind(div.firstChild).model = null;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+      templateBind(div.firstChild).model = 123;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'text');
+    });
   });
 
-  observeTest('Template bind, no parent', () {
+  test('oneTime-Bind', () {
+    var div = createTestHtml('<template bind="[[ bound ]]">text</template>');
+    var model = toObservable({'bound': 1});
+    templateBind(div.firstChild).model = model;
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'text');
+
+      model['bound'] = false;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'text');
+    });
+  });
+
+  test('Bind - no parent', () {
     var div = createTestHtml('<template bind>text</template>');
     var template = div.firstChild;
     template.remove();
 
     templateBind(template).model = {};
-    performMicrotaskCheckpoint();
-    expect(template.nodes.length, 0);
-    expect(template.nextNode, null);
+    return new Future(() {
+      expect(template.nodes.length, 0);
+      expect(template.nextNode, null);
+    });
   });
 
-  observeTest('Template bind, no defaultView', () {
+  test('Bind - no defaultView', () {
     var div = createTestHtml('<template bind>text</template>');
     var template = div.firstChild;
     var doc = document.implementation.createHtmlDocument('');
     doc.adoptNode(div);
     recursivelySetTemplateModel(template, {});
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    return new Future(() => expect(div.nodes.length, 1));
   });
 
-  observeTest('Template-Empty Bind', () {
+  test('Empty Bind', () {
     var div = createTestHtml('<template bind>text</template>');
     var template = div.firstChild;
     templateBind(template).model = {};
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.text, 'text');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'text');
+    });
   });
 
-  observeTest('Template Bind If', () {
-    var div = createTestHtml('<template bind if="{{ foo }}">text</template>');
-    // Note: changed this value from 0->null because zero is not falsey in Dart.
+  test('Bind If', () {
+    var div = createTestHtml(
+        '<template bind="{{ bound }}" if="{{ predicate }}">'
+          'value:{{ value }}'
+        '</template>');
+    // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart.
     // See https://code.google.com/p/dart/issues/detail?id=11956
-    var m = toObservable({ 'foo': null });
+    // Changed bound from null->1 since null is equivalent to JS undefined,
+    // and would cause the template to not be expanded.
+    var m = toObservable({ 'predicate': null, 'bound': 1 });
     var template = div.firstChild;
     templateBind(template).model = m;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    return new Future(() {
+      expect(div.nodes.length, 1);
 
-    m['foo'] = 1;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.lastChild.text, 'text');
+      m['predicate'] = 1;
 
-    templateBind(template).model = null;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:');
+
+      m['bound'] = toObservable({ 'value': 2 });
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:2');
+
+      m['bound']['value'] = 3;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:3');
+
+      templateBind(template).model = null;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
   });
 
-  observeTest('Template Bind If, 2', () {
+  test('Bind oneTime-If - predicate false', () {
+    var div = createTestHtml(
+        '<template bind="{{ bound }}" if="[[ predicate ]]">'
+          'value:{{ value }}'
+        '</template>');
+    // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart.
+    // See https://code.google.com/p/dart/issues/detail?id=11956
+    // Changed bound from null->1 since null is equivalent to JS undefined,
+    // and would cause the template to not be expanded.
+    var m = toObservable({ 'predicate': null, 'bound': 1 });
+    var template = div.firstChild;
+    templateBind(template).model = m;
+
+    return new Future(() {
+      expect(div.nodes.length, 1);
+
+      m['predicate'] = 1;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+
+      m['bound'] = toObservable({ 'value': 2 });
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+
+      m['bound']['value'] = 3;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+
+      templateBind(template).model = null;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
+  });
+
+  test('Bind oneTime-If - predicate true', () {
+    var div = createTestHtml(
+        '<template bind="{{ bound }}" if="[[ predicate ]]">'
+          'value:{{ value }}'
+        '</template>');
+
+    // Dart note: changed bound from null->1 since null is equivalent to JS
+    // undefined, and would cause the template to not be expanded.
+    var m = toObservable({ 'predicate': 1, 'bound': 1 });
+    var template = div.firstChild;
+    templateBind(template).model = m;
+
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:');
+
+      m['bound'] = toObservable({ 'value': 2 });
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:2');
+
+      m['bound']['value'] = 3;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:3');
+
+      m['predicate'] = null; // will have no effect
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:3');
+
+      templateBind(template).model = null;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
+  });
+
+  test('oneTime-Bind If', () {
+    var div = createTestHtml(
+        '<template bind="[[ bound ]]" if="{{ predicate }}">'
+          'value:{{ value }}'
+        '</template>');
+
+    var m = toObservable({'predicate': null, 'bound': {'value': 2}});
+    var template = div.firstChild;
+    templateBind(template).model = m;
+
+    return new Future(() {
+      expect(div.nodes.length, 1);
+
+      m['predicate'] = 1;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:2');
+
+      m['bound']['value'] = 3;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:3');
+
+      m['bound'] = toObservable({'value': 4 });
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:3');
+
+      templateBind(template).model = null;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
+  });
+
+  test('oneTime-Bind oneTime-If', () {
+    var div = createTestHtml(
+        '<template bind="[[ bound ]]" if="[[ predicate ]]">'
+          'value:{{ value }}'
+        '</template>');
+
+    var m = toObservable({'predicate': 1, 'bound': {'value': 2}});
+    var template = div.firstChild;
+    templateBind(template).model = m;
+
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:2');
+
+      m['bound']['value'] = 3;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:3');
+
+      m['bound'] = toObservable({'value': 4 });
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:3');
+
+      m['predicate'] = false;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'value:3');
+
+      templateBind(template).model = null;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
+  });
+
+  test('Bind If, 2', () {
     var div = createTestHtml(
         '<template bind="{{ foo }}" if="{{ bar }}">{{ bat }}</template>');
     var m = toObservable({ 'bar': null, 'foo': { 'bat': 'baz' } });
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    return new Future(() {
+      expect(div.nodes.length, 1);
 
-    m['bar'] = 1;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.lastChild.text, 'baz');
+      m['bar'] = 1;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'baz');
+    });
   });
 
-  observeTest('Template If', () {
+  test('If', () {
     var div = createTestHtml('<template if="{{ foo }}">{{ value }}</template>');
-    // Note: changed this value from 0->null because zero is not falsey in
-    // Dart. See https://code.google.com/p/dart/issues/detail?id=11956
+    // Dart note: foo changed from 0->null because 0 isn't falsey in Dart.
+    // See https://code.google.com/p/dart/issues/detail?id=11956
     var m = toObservable({ 'foo': null, 'value': 'foo' });
     var template = div.firstChild;
     templateBind(template).model = m;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    return new Future(() {
+      expect(div.nodes.length, 1);
 
-    m['foo'] = 1;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.lastChild.text, 'foo');
+      m['foo'] = 1;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'foo');
 
-    templateBind(template).model = null;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+      templateBind(template).model = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
   });
 
-  observeTest('Template Empty-If', () {
+  test('Empty-If', () {
     var div = createTestHtml('<template if>{{ value }}</template>');
     var m = toObservable({ 'value': 'foo' });
     recursivelySetTemplateModel(div, null);
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    return new Future(() {
+      expect(div.nodes.length, 1);
 
-    recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.lastChild.text, 'foo');
+      recursivelySetTemplateModel(div, m);
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'foo');
+    });
   });
 
-  observeTest('Template Repeat If', () {
+  test('OneTime - simple text', () {
+    var div = createTestHtml('<template bind>[[ value ]]</template>');
+    var m = toObservable({ 'value': 'foo' });
+    recursivelySetTemplateModel(div, m);
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'foo');
+
+      m['value'] = 'bar';
+
+    }).then(endOfMicrotask).then((_) {
+      // unchanged.
+      expect(div.lastChild.text, 'foo');
+    });
+  });
+
+  test('OneTime - compound text', () {
     var div = createTestHtml(
-        '<template repeat="{{ foo }}" if="{{ bar }}">{{ }}</template>');
-    // Note: changed this value from 0->null because zero is not falsey in Dart.
+        '<template bind>[[ foo ]] bar [[ baz ]]</template>');
+    var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' });
+    recursivelySetTemplateModel(div, m);
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'FOO bar BAZ');
+
+      m['foo'] = 'FI';
+      m['baz'] = 'BA';
+
+    }).then(endOfMicrotask).then((_) {
+      // unchanged.
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'FOO bar BAZ');
+    });
+  });
+
+  test('OneTime/Dynamic Mixed - compound text', () {
+    var div = createTestHtml(
+        '<template bind>[[ foo ]] bar {{ baz }}</template>');
+    var m = toObservable({ 'foo': 'FOO', 'baz': 'BAZ' });
+    recursivelySetTemplateModel(div, m);
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'FOO bar BAZ');
+
+      m['foo'] = 'FI';
+      m['baz'] = 'BA';
+
+    }).then(endOfMicrotask).then((_) {
+      // unchanged [[ foo ]].
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.text, 'FOO bar BA');
+    });
+  });
+
+  test('OneTime - simple attribute', () {
+    var div = createTestHtml(
+        '<template bind><div foo="[[ value ]]"></div></template>');
+    var m = toObservable({ 'value': 'foo' });
+    recursivelySetTemplateModel(div, m);
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.attributes['foo'], 'foo');
+
+      m['value'] = 'bar';
+
+    }).then(endOfMicrotask).then((_) {
+      // unchanged.
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.attributes['foo'], 'foo');
+    });
+  });
+
+  test('OneTime - compound attribute', () {
+    var div = createTestHtml(
+        '<template bind>'
+          '<div foo="[[ value ]]:[[ otherValue ]]"></div>'
+        '</template>');
+    var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' });
+    recursivelySetTemplateModel(div, m);
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.attributes['foo'], 'foo:bar');
+
+      m['value'] = 'baz';
+      m['otherValue'] = 'bot';
+
+    }).then(endOfMicrotask).then((_) {
+      // unchanged.
+      expect(div.lastChild.attributes['foo'], 'foo:bar');
+    });
+  });
+
+  test('OneTime/Dynamic mixed - compound attribute', () {
+    var div = createTestHtml(
+        '<template bind>'
+          '<div foo="{{ value }}:[[ otherValue ]]"></div>'
+        '</template>');
+    var m = toObservable({ 'value': 'foo', 'otherValue': 'bar' });
+    recursivelySetTemplateModel(div, m);
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.lastChild.attributes['foo'], 'foo:bar');
+
+      m['value'] = 'baz';
+      m['otherValue'] = 'bot';
+
+    }).then(endOfMicrotask).then((_) {
+      // unchanged [[ otherValue ]].
+      expect(div.lastChild.attributes['foo'], 'baz:bar');
+    });
+  });
+
+  test('Repeat If', () {
+    var div = createTestHtml(
+        '<template repeat="{{ items }}" if="{{ predicate }}">{{}}</template>');
+    // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart.
     // See https://code.google.com/p/dart/issues/detail?id=11956
-    var m = toObservable({ 'bar': null, 'foo': [1, 2, 3] });
+    var m = toObservable({ 'predicate': null, 'items': [1] });
     var template = div.firstChild;
     templateBind(template).model = m;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    return new Future(() {
+      expect(div.nodes.length, 1);
 
-    m['bar'] = 1;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
-    expect(div.nodes[1].text, '1');
-    expect(div.nodes[2].text, '2');
-    expect(div.nodes[3].text, '3');
+      m['predicate'] = 1;
 
-    templateBind(template).model = null;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      m['items']..add(2)..add(3);
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
+      expect(div.nodes[1].text, '1');
+      expect(div.nodes[2].text, '2');
+      expect(div.nodes[3].text, '3');
+
+      m['items'] = [4];
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '4');
+
+      templateBind(template).model = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
   });
 
-  observeTest('TextTemplateWithNullStringBinding', () {
+  test('Repeat oneTime-If (predicate false)', () {
+    var div = createTestHtml(
+        '<template repeat="{{ items }}" if="[[ predicate ]]">{{}}</template>');
+    // Dart note: predicate changed from 0->null because 0 isn't falsey in Dart.
+    // See https://code.google.com/p/dart/issues/detail?id=11956
+    var m = toObservable({ 'predicate': null, 'items': [1] });
+    var template = div.firstChild;
+    templateBind(template).model = m;
+    return new Future(() {
+      expect(div.nodes.length, 1);
+
+      m['predicate'] = 1;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1, reason: 'unchanged');
+
+      m['items']..add(2)..add(3);
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1, reason: 'unchanged');
+
+      m['items'] = [4];
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1, reason: 'unchanged');
+
+      templateBind(template).model = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
+  });
+
+  test('Repeat oneTime-If (predicate true)', () {
+    var div = createTestHtml(
+        '<template repeat="{{ items }}" if="[[ predicate ]]">{{}}</template>');
+
+    var m = toObservable({ 'predicate': true, 'items': [1] });
+    var template = div.firstChild;
+    templateBind(template).model = m;
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      m['items']..add(2)..add(3);
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
+      expect(div.nodes[1].text, '1');
+      expect(div.nodes[2].text, '2');
+      expect(div.nodes[3].text, '3');
+
+      m['items'] = [4];
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '4');
+
+      m['predicate'] = false;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2, reason: 'unchanged');
+      expect(div.nodes[1].text, '4', reason: 'unchanged');
+
+      templateBind(template).model = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
+  });
+
+  test('oneTime-Repeat If', () {
+    var div = createTestHtml(
+        '<template repeat="[[ items ]]" if="{{ predicate }}">{{}}</template>');
+
+    var m = toObservable({ 'predicate': false, 'items': [1] });
+    var template = div.firstChild;
+    templateBind(template).model = m;
+    return new Future(() {
+      expect(div.nodes.length, 1);
+
+      m['predicate'] = true;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      m['items']..add(2)..add(3);
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      m['items'] = [4];
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      templateBind(template).model = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
+  });
+
+  test('oneTime-Repeat oneTime-If', () {
+    var div = createTestHtml(
+        '<template repeat="[[ items ]]" if="[[ predicate ]]">{{}}</template>');
+
+    var m = toObservable({ 'predicate': true, 'items': [1] });
+    var template = div.firstChild;
+    templateBind(template).model = m;
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      m['items']..add(2)..add(3);
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      m['items'] = [4];
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      m['predicate'] = false;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes[1].text, '1');
+
+      templateBind(template).model = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
+  });
+
+  test('TextTemplateWithNullStringBinding', () {
     var div = createTestHtml('<template bind={{}}>a{{b}}c</template>');
     var model = toObservable({'b': 'B'});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.text, 'aBc');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'aBc');
 
-    model['b'] = 'b';
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.text, 'abc');
+      model['b'] = 'b';
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.text, 'abc');
 
-    model['b'] = null;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.text, 'ac');
+      model['b'] = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.text, 'ac');
 
-    model = null;
-    performMicrotaskCheckpoint();
-    // setting model isn't observable.
-    expect(div.nodes.last.text, 'ac');
+      model = null;
+    }).then(endOfMicrotask).then((_) {
+      // setting model isn't bindable.
+      expect(div.nodes.last.text, 'ac');
+    });
   });
 
-  observeTest('TextTemplateWithBindingPath', () {
+  test('TextTemplateWithBindingPath', () {
     var div = createTestHtml(
         '<template bind="{{ data }}">a{{b}}c</template>');
     var model = toObservable({ 'data': {'b': 'B'} });
     var template = div.firstChild;
     templateBind(template).model = model;
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.text, 'aBc');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'aBc');
 
-    model['data']['b'] = 'b';
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.text, 'abc');
+      model['data']['b'] = 'b';
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.text, 'abc');
 
-    model['data'] = toObservable({'b': 'X'});
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.text, 'aXc');
+      model['data'] = toObservable({'b': 'X'});
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.text, 'aXc');
 
-    // Dart note: changed from `null` since our null means don't render a model.
-    model['data'] = toObservable({});
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.text, 'ac');
+      // Dart note: changed from `null` since our null means don't render a model.
+      model['data'] = toObservable({});
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.text, 'ac');
 
-    model['data'] = null;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+      model['data'] = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
   });
 
-  observeTest('TextTemplateWithBindingAndConditional', () {
+  test('TextTemplateWithBindingAndConditional', () {
     var div = createTestHtml(
         '<template bind="{{}}" if="{{ d }}">a{{b}}c</template>');
     var model = toObservable({'b': 'B', 'd': 1});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.text, 'aBc');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'aBc');
 
-    model['b'] = 'b';
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.text, 'abc');
+      model['b'] = 'b';
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.text, 'abc');
 
-    // TODO(jmesserly): MDV set this to empty string and relies on JS conversion
-    // rules. Is that intended?
-    // See https://github.com/toolkitchen/mdv/issues/59
-    model['d'] = null;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+      // TODO(jmesserly): MDV set this to empty string and relies on JS conversion
+      // rules. Is that intended?
+      // See https://github.com/Polymer/TemplateBinding/issues/59
+      model['d'] = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
 
-    model['d'] = 'here';
-    model['b'] = 'd';
+      model['d'] = 'here';
+      model['b'] = 'd';
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.text, 'adc');
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'adc');
+    });
   });
 
-  observeTest('TemplateWithTextBinding2', () {
+  test('TemplateWithTextBinding2', () {
     var div = createTestHtml(
         '<template bind="{{ b }}">a{{value}}c</template>');
     expect(div.nodes.length, 1);
     var model = toObservable({'b': {'value': 'B'}});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.text, 'aBc');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.text, 'aBc');
 
-    model['b'] = toObservable({'value': 'b'});
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.text, 'abc');
+      model['b'] = toObservable({'value': 'b'});
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.text, 'abc');
+    });
   });
 
-  observeTest('TemplateWithAttributeBinding', () {
+  test('TemplateWithAttributeBinding', () {
     var div = createTestHtml(
         '<template bind="{{}}">'
         '<div foo="a{{b}}c"></div>'
@@ -316,20 +788,21 @@
     var model = toObservable({'b': 'B'});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.attributes['foo'], 'aBc');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.attributes['foo'], 'aBc');
 
-    model['b'] = 'b';
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.attributes['foo'], 'abc');
+      model['b'] = 'b';
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.attributes['foo'], 'abc');
 
-    model['b'] = 'X';
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.attributes['foo'], 'aXc');
+      model['b'] = 'X';
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.attributes['foo'], 'aXc');
+    });
   });
 
-  observeTest('TemplateWithConditionalBinding', () {
+  test('TemplateWithConditionalBinding', () {
     var div = createTestHtml(
         '<template bind="{{}}">'
         '<div foo?="{{b}}"></div>'
@@ -337,40 +810,91 @@
     var model = toObservable({'b': 'b'});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.attributes['foo'], '');
-    expect(div.nodes.last.attributes, isNot(contains('foo?')));
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.attributes['foo'], '');
+      expect(div.nodes.last.attributes, isNot(contains('foo?')));
 
-    model['b'] = null;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.attributes, isNot(contains('foo')));
+      model['b'] = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.attributes, isNot(contains('foo')));
+    });
   });
 
-  observeTest('Repeat', () {
+  test('Repeat', () {
     var div = createTestHtml(
-        '<template repeat="{{}}"">text</template>');
+        '<template repeat="{{ array }}">{{}},</template>');
+
+    var model = toObservable({'array': [0, 1, 2]});
+    var template = templateBind(div.firstChild);
+    template.model = model;
+
+    return new Future(() {
+      expect(div.nodes.length, 4);
+      expect(div.text, '0,1,2,');
+
+      model['array'].length = 1;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
+      expect(div.text, '0,');
+
+      model['array'].addAll([3, 4]);
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
+      expect(div.text, '0,3,4,');
+
+      model['array'].removeRange(1, 2);
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 3);
+      expect(div.text, '0,4,');
+
+      model['array'].addAll([5, 6]);
+      model['array'] = toObservable(['x', 'y']);
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 3);
+      expect(div.text, 'x,y,');
+
+      template.model = null;
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+      expect(div.text, '');
+    });
+  });
+
+  test('Repeat - oneTime', () {
+    var div = createTestHtml('<template repeat="[[]]">text</template>');
 
     var model = toObservable([0, 1, 2]);
-    recursivelySetTemplateModel(div, model);
+    var template = templateBind(div.firstChild);
+    template.model = model;
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
+    return new Future(() {
+      expect(div.nodes.length, 4);
 
-    model.length = 1;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
+      model.length = 1;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
 
-    model.addAll(toObservable([3, 4]));
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
+      model.addAll([3, 4]);
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
 
-    model.removeRange(1, 2);
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 3);
+      model.removeRange(1, 2);
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
+
+      template.model = null;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
+    });
   });
 
-  observeTest('Repeat - Reuse Instances', () {
+  test('Repeat - Reuse Instances', () {
     var div = createTestHtml('<template repeat>{{ val }}</template>');
 
     var model = toObservable([
@@ -381,157 +905,164 @@
       {'val': 1}
     ]);
     recursivelySetTemplateModel(div, model);
-
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 6);
     var template = div.firstChild;
 
-    addExpandos(template.nextNode);
-    checkExpandos(template.nextNode);
+    return new Future(() {
+      expect(div.nodes.length, 6);
 
-    model.sort((a, b) => a['val'] - b['val']);
-    performMicrotaskCheckpoint();
-    checkExpandos(template.nextNode);
+      addExpandos(template.nextNode);
+      checkExpandos(template.nextNode);
 
-    model = toObservable(model.reversed);
-    recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-    checkExpandos(template.nextNode);
+      model.sort((a, b) => a['val'] - b['val']);
+    }).then(endOfMicrotask).then((_) {
+      checkExpandos(template.nextNode);
 
-    for (var item in model) {
-      item['val'] += 1;
-    }
+      model = toObservable(model.reversed);
+      recursivelySetTemplateModel(div, model);
+    }).then(endOfMicrotask).then((_) {
+      checkExpandos(template.nextNode);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes[1].text, "11");
-    expect(div.nodes[2].text, "9");
-    expect(div.nodes[3].text, "6");
-    expect(div.nodes[4].text, "3");
-    expect(div.nodes[5].text, "2");
+      for (var item in model) {
+        item['val'] += 1;
+      }
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes[1].text, "11");
+      expect(div.nodes[2].text, "9");
+      expect(div.nodes[3].text, "6");
+      expect(div.nodes[4].text, "3");
+      expect(div.nodes[5].text, "2");
+    });
   });
 
-  observeTest('Bind - Reuse Instance', () {
+  test('Bind - Reuse Instance', () {
     var div = createTestHtml(
         '<template bind="{{ foo }}">{{ bar }}</template>');
 
     var model = toObservable({ 'foo': { 'bar': 5 }});
     recursivelySetTemplateModel(div, model);
-
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
     var template = div.firstChild;
 
-    addExpandos(template.nextNode);
-    checkExpandos(template.nextNode);
+    return new Future(() {
+      expect(div.nodes.length, 2);
 
-    model = toObservable({'foo': model['foo']});
-    recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-    checkExpandos(template.nextNode);
+      addExpandos(template.nextNode);
+      checkExpandos(template.nextNode);
+
+      model = toObservable({'foo': model['foo']});
+      recursivelySetTemplateModel(div, model);
+    }).then(endOfMicrotask).then((_) {
+      checkExpandos(template.nextNode);
+    });
   });
 
-  observeTest('Repeat-Empty', () {
+  test('Repeat-Empty', () {
     var div = createTestHtml(
         '<template repeat>text</template>');
 
     var model = toObservable([0, 1, 2]);
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
+    return new Future(() {
+      expect(div.nodes.length, 4);
 
-    model.length = 1;
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
+      model.length = 1;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 2);
 
-    model.addAll(toObservable([3, 4]));
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
+      model.addAll(toObservable([3, 4]));
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
 
-    model.removeRange(1, 2);
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 3);
+      model.removeRange(1, 2);
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 3);
+    });
   });
 
-  observeTest('Removal from iteration needs to unbind', () {
+  test('Removal from iteration needs to unbind', () {
     var div = createTestHtml(
         '<template repeat="{{}}"><a>{{v}}</a></template>');
     var model = toObservable([{'v': 0}, {'v': 1}, {'v': 2}, {'v': 3},
         {'v': 4}]);
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
 
-    var nodes = div.nodes.skip(1).toList();
-    var vs = model.toList();
+    var nodes, vs;
+    return new Future(() {
 
-    for (var i = 0; i < 5; i++) {
-      expect(nodes[i].text, '$i');
-    }
+      nodes = div.nodes.skip(1).toList();
+      vs = model.toList();
 
-    model.length = 3;
-    performMicrotaskCheckpoint();
-    for (var i = 0; i < 5; i++) {
-      expect(nodes[i].text, '$i');
-    }
+      for (var i = 0; i < 5; i++) {
+        expect(nodes[i].text, '$i');
+      }
 
-    vs[3]['v'] = 33;
-    vs[4]['v'] = 44;
-    performMicrotaskCheckpoint();
-    for (var i = 0; i < 5; i++) {
-      expect(nodes[i].text, '$i');
-    }
+      model.length = 3;
+    }).then(endOfMicrotask).then((_) {
+      for (var i = 0; i < 5; i++) {
+        expect(nodes[i].text, '$i');
+      }
+
+      vs[3]['v'] = 33;
+      vs[4]['v'] = 44;
+    }).then(endOfMicrotask).then((_) {
+      for (var i = 0; i < 5; i++) {
+        expect(nodes[i].text, '$i');
+      }
+    });
   });
 
-  observeTest('DOM Stability on Iteration', () {
+  test('DOM Stability on Iteration', () {
     var div = createTestHtml(
         '<template repeat="{{}}">{{}}</template>');
     var model = toObservable([1, 2, 3, 4, 5]);
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
+    var nodes;
+    return new Future(() {
+      // Note: the node at index 0 is the <template>.
+      nodes = div.nodes.toList();
+      expect(nodes.length, 6, reason: 'list has 5 items');
 
-    // Note: the node at index 0 is the <template>.
-    var nodes = div.nodes.toList();
-    expect(nodes.length, 6, reason: 'list has 5 items');
+      model.removeAt(0);
+      model.removeLast();
 
-    model.removeAt(0);
-    model.removeLast();
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4, reason: 'list has 3 items');
+      expect(identical(div.nodes[1], nodes[2]), true, reason: '2 not removed');
+      expect(identical(div.nodes[2], nodes[3]), true, reason: '3 not removed');
+      expect(identical(div.nodes[3], nodes[4]), true, reason: '4 not removed');
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4, reason: 'list has 3 items');
-    expect(identical(div.nodes[1], nodes[2]), true, reason: '2 not removed');
-    expect(identical(div.nodes[2], nodes[3]), true, reason: '3 not removed');
-    expect(identical(div.nodes[3], nodes[4]), true, reason: '4 not removed');
+      model.insert(0, 5);
+      model[2] = 6;
+      model.add(7);
 
-    model.insert(0, 5);
-    model[2] = 6;
-    model.add(7);
+    }).then(endOfMicrotask).then((_) {
 
-    performMicrotaskCheckpoint();
+      expect(div.nodes.length, 6, reason: 'list has 5 items');
+      expect(nodes.contains(div.nodes[1]), false, reason: '5 is a new node');
+      expect(identical(div.nodes[2], nodes[2]), true);
+      expect(nodes.contains(div.nodes[3]), false, reason: '6 is a new node');
+      expect(identical(div.nodes[4], nodes[4]), true);
+      expect(nodes.contains(div.nodes[5]), false, reason: '7 is a new node');
 
-    expect(div.nodes.length, 6, reason: 'list has 5 items');
-    expect(nodes.contains(div.nodes[1]), false, reason: '5 is a new node');
-    expect(identical(div.nodes[2], nodes[2]), true);
-    expect(nodes.contains(div.nodes[3]), false, reason: '6 is a new node');
-    expect(identical(div.nodes[4], nodes[4]), true);
-    expect(nodes.contains(div.nodes[5]), false, reason: '7 is a new node');
+      nodes = div.nodes.toList();
 
-    nodes = div.nodes.toList();
+      model.insert(2, 8);
 
-    model.insert(2, 8);
+    }).then(endOfMicrotask).then((_) {
 
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes.length, 7, reason: 'list has 6 items');
-    expect(identical(div.nodes[1], nodes[1]), true);
-    expect(identical(div.nodes[2], nodes[2]), true);
-    expect(nodes.contains(div.nodes[3]), false, reason: '8 is a new node');
-    expect(identical(div.nodes[4], nodes[3]), true);
-    expect(identical(div.nodes[5], nodes[4]), true);
-    expect(identical(div.nodes[6], nodes[5]), true);
+      expect(div.nodes.length, 7, reason: 'list has 6 items');
+      expect(identical(div.nodes[1], nodes[1]), true);
+      expect(identical(div.nodes[2], nodes[2]), true);
+      expect(nodes.contains(div.nodes[3]), false, reason: '8 is a new node');
+      expect(identical(div.nodes[4], nodes[3]), true);
+      expect(identical(div.nodes[5], nodes[4]), true);
+      expect(identical(div.nodes[6], nodes[5]), true);
+    });
   });
 
-  observeTest('Repeat2', () {
+  test('Repeat2', () {
     var div = createTestHtml(
         '<template repeat="{{}}">{{value}}</template>');
     expect(div.nodes.length, 1);
@@ -543,28 +1074,29 @@
     ]);
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
-    expect(div.nodes[1].text, '0');
-    expect(div.nodes[2].text, '1');
-    expect(div.nodes[3].text, '2');
+    return new Future(() {
+      expect(div.nodes.length, 4);
+      expect(div.nodes[1].text, '0');
+      expect(div.nodes[2].text, '1');
+      expect(div.nodes[3].text, '2');
 
-    model[1]['value'] = 'One';
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
-    expect(div.nodes[1].text, '0');
-    expect(div.nodes[2].text, 'One');
-    expect(div.nodes[3].text, '2');
+      model[1]['value'] = 'One';
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
+      expect(div.nodes[1].text, '0');
+      expect(div.nodes[2].text, 'One');
+      expect(div.nodes[3].text, '2');
 
-    model.replaceRange(0, 1, toObservable([{'value': 'Zero'}]));
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
-    expect(div.nodes[1].text, 'Zero');
-    expect(div.nodes[2].text, 'One');
-    expect(div.nodes[3].text, '2');
+      model.replaceRange(0, 1, toObservable([{'value': 'Zero'}]));
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 4);
+      expect(div.nodes[1].text, 'Zero');
+      expect(div.nodes[2].text, 'One');
+      expect(div.nodes[3].text, '2');
+    });
   });
 
-  observeTest('TemplateWithInputValue', () {
+  test('TemplateWithInputValue', () {
     var div = createTestHtml(
         '<template bind="{{}}">'
         '<input value="{{x}}">'
@@ -572,25 +1104,26 @@
     var model = toObservable({'x': 'hi'});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes.last.value, 'hi');
+    return new Future(() {
+      expect(div.nodes.length, 2);
+      expect(div.nodes.last.value, 'hi');
 
-    model['x'] = 'bye';
-    expect(div.nodes.last.value, 'hi');
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.value, 'bye');
+      model['x'] = 'bye';
+      expect(div.nodes.last.value, 'hi');
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.value, 'bye');
 
-    div.nodes.last.value = 'hello';
-    dispatchEvent('input', div.nodes.last);
-    expect(model['x'], 'hello');
-    performMicrotaskCheckpoint();
-    expect(div.nodes.last.value, 'hello');
+      div.nodes.last.value = 'hello';
+      dispatchEvent('input', div.nodes.last);
+      expect(model['x'], 'hello');
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.last.value, 'hello');
+    });
   });
 
 //////////////////////////////////////////////////////////////////////////////
 
-  observeTest('Decorated', () {
+  test('Decorated', () {
     var div = createTestHtml(
         '<template bind="{{ XX }}" id="t1">'
           '<p>Crew member: {{name}}, Job title: {{title}}</p>'
@@ -604,24 +1137,24 @@
     });
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
+    return new Future(() {
+      var t1 = document.getElementById('t1');
+      var instance = t1.nextElementSibling;
+      expect(instance.text, 'Crew member: Leela, Job title: Captain');
 
-    var t1 = document.getElementById('t1');
-    var instance = t1.nextElementSibling;
-    expect(instance.text, 'Crew member: Leela, Job title: Captain');
+      var t2 = document.getElementById('t2');
+      instance = t2.nextElementSibling;
+      expect(instance.text, 'Crew member: Fry, Job title: Delivery boy');
 
-    var t2 = document.getElementById('t2');
-    instance = t2.nextElementSibling;
-    expect(instance.text, 'Crew member: Fry, Job title: Delivery boy');
+      expect(div.children.length, 4);
+      expect(div.nodes.length, 4);
 
-    expect(div.children.length, 4);
-    expect(div.nodes.length, 4);
-
-    expect(div.nodes[1].tagName, 'P');
-    expect(div.nodes[3].tagName, 'P');
+      expect(div.nodes[1].tagName, 'P');
+      expect(div.nodes[3].tagName, 'P');
+    });
   });
 
-  observeTest('DefaultStyles', () {
+  test('DefaultStyles', () {
     var t = new Element.tag('template');
     TemplateBindExtension.decorate(t);
 
@@ -632,40 +1165,24 @@
   });
 
 
-  observeTest('Bind', () {
+  test('Bind', () {
     var div = createTestHtml('<template bind="{{}}">Hi {{ name }}</template>');
     var model = toObservable({'name': 'Leela'});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes[1].text, 'Hi Leela');
+    return new Future(() => expect(div.nodes[1].text, 'Hi Leela'));
   });
 
-  observeTest('BindImperative', () {
-    var div = createTestHtml(
-        '<template>'
-          'Hi {{ name }}'
-        '</template>');
-    var t = div.nodes.first;
-
-    var model = toObservable({'name': 'Leela'});
-    nodeBind(t).bind('bind', model, '');
-
-    performMicrotaskCheckpoint();
-    expect(div.nodes[1].text, 'Hi Leela');
-  });
-
-  observeTest('BindPlaceHolderHasNewLine', () {
+  test('BindPlaceHolderHasNewLine', () {
     var div = createTestHtml(
         '<template bind="{{}}">Hi {{\nname\n}}</template>');
     var model = toObservable({'name': 'Leela'});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(div.nodes[1].text, 'Hi Leela');
+    return new Future(() => expect(div.nodes[1].text, 'Hi Leela'));
   });
 
-  observeTest('BindWithRef', () {
+  test('BindWithRef', () {
     var id = 't${new math.Random().nextInt(100)}';
     var div = createTestHtml(
         '<template id="$id">'
@@ -681,11 +1198,35 @@
     var model = toObservable({'name': 'Fry'});
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(t2.nextNode.text, 'Hi Fry');
+    return new Future(() => expect(t2.nextNode.text, 'Hi Fry'));
   });
 
-  observeTest('BindWithDynamicRef', () {
+
+  test('Update Ref', () {
+    var div = createTestHtml(
+        '<template id=A>Hi, {{}}</template>'
+        '<template id=B>Hola, {{}}</template>'
+        '<template ref=A repeat></template>');
+
+    var model = new ObservableList.from(['Fry']);
+    recursivelySetTemplateModel(div, model);
+
+    return new Future(() {
+      expect(div.nodes.length, 4);
+      expect('Hi, Fry', div.nodes[3].text);
+
+      div.nodes[2].attributes['ref'] = 'B';
+      model.add('Leela');
+
+    }).then(endOfMicrotask).then((x) {
+      expect(div.nodes.length, 5);
+
+      expect('Hi, Fry', div.nodes[3].text);
+      expect('Hola, Leela', div.nodes[4].text);
+    });
+  });
+
+  test('BindWithDynamicRef', () {
     var id = 't${new math.Random().nextInt(100)}';
     var div = createTestHtml(
         '<template id="$id">'
@@ -698,33 +1239,7 @@
     var model = toObservable({'name': 'Fry', 'id': id });
     recursivelySetTemplateModel(div, model);
 
-    performMicrotaskCheckpoint();
-    expect(t2.nextNode.text, 'Hi Fry');
-  });
-
-  observeTest('BindChanged', () {
-    var model = toObservable({
-      'XX': {'name': 'Leela', 'title': 'Captain'},
-      'XY': {'name': 'Fry', 'title': 'Delivery boy'},
-      'XZ': {'name': 'Zoidberg', 'title': 'Doctor'}
-    });
-
-    var div = createTestHtml(
-        '<template bind="{{ XX }}">Hi {{ name }}</template>');
-
-    recursivelySetTemplateModel(div, model);
-
-    var t = div.nodes.first;
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes.length, 2);
-    expect(t.nextNode.text, 'Hi Leela');
-
-    nodeBind(t).bind('bind', model, 'XZ');
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes.length, 2);
-    expect(t.nextNode.text, 'Hi Zoidberg');
+    return new Future(() => expect(t2.nextNode.text, 'Hi Fry'));
   });
 
   assertNodesAre(div, [arguments]) {
@@ -737,7 +1252,7 @@
     }
   }
 
-  observeTest('Repeat3', () {
+  test('Repeat3', () {
     var div = createTestHtml(
         '<template repeat="{{ contacts }}">Hi {{ name }}</template>');
     var t = div.nodes.first;
@@ -751,44 +1266,45 @@
     });
 
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
 
-    assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
 
-    m['contacts'].add(toObservable({'name': 'Alex'}));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
+      m['contacts'].add(toObservable({'name': 'Alex'}));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
 
-    m['contacts'].replaceRange(0, 2,
-        toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
+      m['contacts'].replaceRange(0, 2,
+          toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
 
-    m['contacts'].removeRange(1, 3);
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
+      m['contacts'].removeRange(1, 3);
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
 
-    m['contacts'].insertAll(1,
-        toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
+      m['contacts'].insertAll(1,
+          toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
 
-    m['contacts'].replaceRange(0, 1,
-        toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
-        'Hi Alex']);
+      m['contacts'].replaceRange(0, 1,
+          toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
+          'Hi Alex']);
 
-    m['contacts'] = toObservable([{'name': 'Alex'}]);
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Alex']);
+      m['contacts'] = toObservable([{'name': 'Alex'}]);
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Alex']);
 
-    m['contacts'].length = 0;
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, []);
+      m['contacts'].length = 0;
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, []);
+    });
   });
 
-  observeTest('RepeatModelSet', () {
+  test('RepeatModelSet', () {
     var div = createTestHtml(
         '<template repeat="{{ contacts }}">'
           'Hi {{ name }}'
@@ -801,14 +1317,13 @@
       ]
     });
     recursivelySetTemplateModel(div, m);
-
-    performMicrotaskCheckpoint();
-    var t = div.nodes.first;
-
-    assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+    return new Future(() {
+      var t = div.nodes.first;
+      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+    });
   });
 
-  observeTest('RepeatEmptyPath', () {
+  test('RepeatEmptyPath', () {
     var div = createTestHtml(
         '<template repeat="{{}}">Hi {{ name }}</template>');
     var t = div.nodes.first;
@@ -819,39 +1334,39 @@
       {'name': 'Neal'}
     ]);
     recursivelySetTemplateModel(div, m);
+    return new Future(() {
 
-    performMicrotaskCheckpoint();
+      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
 
-    assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+      m.add(toObservable({'name': 'Alex'}));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
 
-    m.add(toObservable({'name': 'Alex'}));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal', 'Hi Alex']);
+      m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
 
-    m.replaceRange(0, 2, toObservable([{'name': 'Rafael'}, {'name': 'Erik'}]));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Neal', 'Hi Alex']);
+      m.removeRange(1, 3);
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
 
-    m.removeRange(1, 3);
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Rafael', 'Hi Alex']);
+      m.insertAll(1, toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
 
-    m.insertAll(1, toObservable([{'name': 'Erik'}, {'name': 'Dimitri'}]));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Rafael', 'Hi Erik', 'Hi Dimitri', 'Hi Alex']);
+      m.replaceRange(0, 1, toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
+          'Hi Alex']);
 
-    m.replaceRange(0, 1, toObservable([{'name': 'Tab'}, {'name': 'Neal'}]));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Tab', 'Hi Neal', 'Hi Erik', 'Hi Dimitri',
-        'Hi Alex']);
-
-    m.length = 0;
-    m.add(toObservable({'name': 'Alex'}));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Alex']);
+      m.length = 0;
+      m.add(toObservable({'name': 'Alex'}));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Alex']);
+    });
   });
 
-  observeTest('RepeatNullModel', () {
+  test('RepeatNullModel', () {
     var div = createTestHtml(
         '<template repeat="{{}}">Hi {{ name }}</template>');
     var t = div.nodes.first;
@@ -864,12 +1379,10 @@
     t.attributes['iterate'] = '';
     m = toObservable({});
     recursivelySetTemplateModel(div, m);
-
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+    return new Future(() => expect(div.nodes.length, 1));
   });
 
-  observeTest('RepeatReuse', () {
+  test('RepeatReuse', () {
     var div = createTestHtml(
         '<template repeat="{{}}">Hi {{ name }}</template>');
     var t = div.nodes.first;
@@ -880,60 +1393,61 @@
       {'name': 'Neal'}
     ]);
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
 
-    assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
-    var node1 = div.nodes[1];
-    var node2 = div.nodes[2];
-    var node3 = div.nodes[3];
+    var node1, node2, node3;
+    return new Future(() {
+      assertNodesAre(div, ['Hi Raf', 'Hi Arv', 'Hi Neal']);
+      node1 = div.nodes[1];
+      node2 = div.nodes[2];
+      node3 = div.nodes[3];
 
-    m.replaceRange(1, 2, toObservable([{'name': 'Erik'}]));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']);
-    expect(div.nodes[1], node1,
-        reason: 'model[0] did not change so the node should not have changed');
-    expect(div.nodes[2], isNot(equals(node2)),
-        reason: 'Should not reuse when replacing');
-    expect(div.nodes[3], node3,
-        reason: 'model[2] did not change so the node should not have changed');
+      m.replaceRange(1, 2, toObservable([{'name': 'Erik'}]));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Raf', 'Hi Erik', 'Hi Neal']);
+      expect(div.nodes[1], node1,
+          reason: 'model[0] did not change so the node should not have changed');
+      expect(div.nodes[2], isNot(equals(node2)),
+          reason: 'Should not reuse when replacing');
+      expect(div.nodes[3], node3,
+          reason: 'model[2] did not change so the node should not have changed');
 
-    node2 = div.nodes[2];
-    m.insert(0, toObservable({'name': 'Alex'}));
-    performMicrotaskCheckpoint();
-    assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']);
+      node2 = div.nodes[2];
+      m.insert(0, toObservable({'name': 'Alex'}));
+    }).then(endOfMicrotask).then((_) {
+      assertNodesAre(div, ['Hi Alex', 'Hi Raf', 'Hi Erik', 'Hi Neal']);
+    });
   });
 
-  observeTest('TwoLevelsDeepBug', () {
+  test('TwoLevelsDeepBug', () {
     var div = createTestHtml(
       '<template bind="{{}}"><span><span>{{ foo }}</span></span></template>');
 
     var model = toObservable({'foo': 'bar'});
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes[1].nodes[0].nodes[0].text, 'bar');
+    return new Future(() {
+      expect(div.nodes[1].nodes[0].nodes[0].text, 'bar');
+    });
   });
 
-  observeTest('Checked', () {
+  test('Checked', () {
     var div = createTestHtml(
-        '<template>'
+        '<template bind>'
           '<input type="checkbox" checked="{{a}}">'
         '</template>');
     var t = div.nodes.first;
-    var m = toObservable({
-      'a': true
+    templateBind(t).model = toObservable({'a': true });
+
+    return new Future(() {
+
+      var instanceInput = t.nextNode;
+      expect(instanceInput.checked, true);
+
+      instanceInput.click();
+      expect(instanceInput.checked, false);
+
+      instanceInput.click();
+      expect(instanceInput.checked, true);
     });
-    nodeBind(t).bind('bind', m, '');
-    performMicrotaskCheckpoint();
-
-    var instanceInput = t.nextNode;
-    expect(instanceInput.checked, true);
-
-    instanceInput.click();
-    expect(instanceInput.checked, false);
-
-    instanceInput.click();
-    expect(instanceInput.checked, true);
   });
 
   nestedHelper(s, start) {
@@ -947,40 +1461,37 @@
     });
 
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
 
-    var i = start;
-    expect(div.nodes[i++].text, '1');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, '2');
+      var i = start;
+      expect(div.nodes[i++].text, '1');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, '2');
 
-    m['a']['b'] = 11;
-    performMicrotaskCheckpoint();
-    expect(div.nodes[start].text, '11');
+      m['a']['b'] = 11;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes[start].text, '11');
 
-    m['a']['c'] = toObservable({'d': 22});
-    performMicrotaskCheckpoint();
-    expect(div.nodes[start + 2].text, '22');
+      m['a']['c'] = toObservable({'d': 22});
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes[start + 2].text, '22');
+    });
   }
 
-  observeTest('Nested', () {
-    nestedHelper(
-        '<template bind="{{a}}">'
-          '{{b}}'
-          '<template bind="{{c}}">'
-            '{{d}}'
-          '</template>'
-        '</template>', 1);
-  });
+  test('Nested', () => nestedHelper(
+      '<template bind="{{a}}">'
+        '{{b}}'
+        '<template bind="{{c}}">'
+          '{{d}}'
+        '</template>'
+      '</template>', 1));
 
-  observeTest('NestedWithRef', () {
-    nestedHelper(
+  test('NestedWithRef', () => nestedHelper(
         '<template id="inner">{{d}}</template>'
         '<template id="outer" bind="{{a}}">'
           '{{b}}'
           '<template ref="inner" bind="{{c}}"></template>'
-        '</template>', 2);
-  });
+        '</template>', 2));
 
   nestedIterateInstantiateHelper(s, start) {
     var div = createTestHtml(s);
@@ -999,46 +1510,43 @@
     });
 
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
 
-    var i = start;
-    expect(div.nodes[i++].text, '1');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, '11');
-    expect(div.nodes[i++].text, '2');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, '22');
+      var i = start;
+      expect(div.nodes[i++].text, '1');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, '11');
+      expect(div.nodes[i++].text, '2');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, '22');
 
-    m['a'][1] = toObservable({
-      'b': 3,
-      'c': {'d': 33}
+      m['a'][1] = toObservable({
+        'b': 3,
+        'c': {'d': 33}
+      });
+
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes[start + 3].text, '3');
+      expect(div.nodes[start + 5].text, '33');
     });
-
-    performMicrotaskCheckpoint();
-    expect(div.nodes[start + 3].text, '3');
-    expect(div.nodes[start + 5].text, '33');
   }
 
-  observeTest('NestedRepeatBind', () {
-    nestedIterateInstantiateHelper(
-        '<template repeat="{{a}}">'
-          '{{b}}'
-          '<template bind="{{c}}">'
-            '{{d}}'
-          '</template>'
-        '</template>', 1);
-  });
-
-  observeTest('NestedRepeatBindWithRef', () {
-    nestedIterateInstantiateHelper(
-        '<template id="inner">'
+  test('NestedRepeatBind', () => nestedIterateInstantiateHelper(
+      '<template repeat="{{a}}">'
+        '{{b}}'
+        '<template bind="{{c}}">'
           '{{d}}'
         '</template>'
-        '<template repeat="{{a}}">'
-          '{{b}}'
-          '<template ref="inner" bind="{{c}}"></template>'
-        '</template>', 2);
-  });
+      '</template>', 1));
+
+  test('NestedRepeatBindWithRef', () => nestedIterateInstantiateHelper(
+      '<template id="inner">'
+        '{{d}}'
+      '</template>'
+      '<template repeat="{{a}}">'
+        '{{b}}'
+        '<template ref="inner" bind="{{c}}"></template>'
+      '</template>', 2));
 
   nestedIterateIterateHelper(s, start) {
     var div = createTestHtml(s);
@@ -1057,53 +1565,50 @@
     });
 
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
 
-    var i = start;
-    expect(div.nodes[i++].text, '1');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, '11');
-    expect(div.nodes[i++].text, '12');
-    expect(div.nodes[i++].text, '2');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, '21');
-    expect(div.nodes[i++].text, '22');
+      var i = start;
+      expect(div.nodes[i++].text, '1');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, '11');
+      expect(div.nodes[i++].text, '12');
+      expect(div.nodes[i++].text, '2');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, '21');
+      expect(div.nodes[i++].text, '22');
 
-    m['a'][1] = toObservable({
-      'b': 3,
-      'c': [{'d': 31}, {'d': 32}, {'d': 33}]
+      m['a'][1] = toObservable({
+        'b': 3,
+        'c': [{'d': 31}, {'d': 32}, {'d': 33}]
+      });
+
+      i = start + 4;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes[start + 4].text, '3');
+      expect(div.nodes[start + 6].text, '31');
+      expect(div.nodes[start + 7].text, '32');
+      expect(div.nodes[start + 8].text, '33');
     });
-
-    i = start + 4;
-    performMicrotaskCheckpoint();
-    expect(div.nodes[start + 4].text, '3');
-    expect(div.nodes[start + 6].text, '31');
-    expect(div.nodes[start + 7].text, '32');
-    expect(div.nodes[start + 8].text, '33');
   }
 
-  observeTest('NestedRepeatBind', () {
-    nestedIterateIterateHelper(
-        '<template repeat="{{a}}">'
-          '{{b}}'
-          '<template repeat="{{c}}">'
-            '{{d}}'
-          '</template>'
-        '</template>', 1);
-  });
-
-  observeTest('NestedRepeatRepeatWithRef', () {
-    nestedIterateIterateHelper(
-        '<template id="inner">'
+  test('NestedRepeatBind', () => nestedIterateIterateHelper(
+      '<template repeat="{{a}}">'
+        '{{b}}'
+        '<template repeat="{{c}}">'
           '{{d}}'
         '</template>'
-        '<template repeat="{{a}}">'
-          '{{b}}'
-          '<template ref="inner" repeat="{{c}}"></template>'
-        '</template>', 2);
-  });
+      '</template>', 1));
 
-  observeTest('NestedRepeatSelfRef', () {
+  test('NestedRepeatRepeatWithRef', () => nestedIterateIterateHelper(
+      '<template id="inner">'
+        '{{d}}'
+      '</template>'
+      '<template repeat="{{a}}">'
+        '{{b}}'
+        '<template ref="inner" repeat="{{c}}"></template>'
+      '</template>', 2));
+
+  test('NestedRepeatSelfRef', () {
     var div = createTestHtml(
         '<template id="t" repeat="{{}}">'
           '{{name}}'
@@ -1135,26 +1640,27 @@
     ]);
 
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
 
-    var i = 1;
-    expect(div.nodes[i++].text, 'Item 1');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, 'Item 1.1');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, 'Item 1.1.1');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, 'Item 1.2');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, 'Item 2');
+    int i = 1;
+    return new Future(() {
+      expect(div.nodes[i++].text, 'Item 1');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, 'Item 1.1');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, 'Item 1.1.1');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, 'Item 1.2');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, 'Item 2');
 
-    m[0] = toObservable({'name': 'Item 1 changed'});
+      m[0] = toObservable({'name': 'Item 1 changed'});
 
-    i = 1;
-    performMicrotaskCheckpoint();
-    expect(div.nodes[i++].text, 'Item 1 changed');
-    expect(div.nodes[i++].tagName, 'TEMPLATE');
-    expect(div.nodes[i++].text, 'Item 2');
+      i = 1;
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes[i++].text, 'Item 1 changed');
+      expect(div.nodes[i++].tagName, 'TEMPLATE');
+      expect(div.nodes[i++].text, 'Item 2');
+    });
   });
 
   // Note: we don't need a zone for this test, and we don't want to alter timing
@@ -1211,8 +1717,8 @@
     return completer.future;
   });
 
-  observeTest('NestedIterateTableMixedSemanticNative', () {
-    if (!parserHasNativeTemplate) return;
+  test('NestedIterateTableMixedSemanticNative', () {
+    if (!parserHasNativeTemplate) return null;
 
     var div = createTestHtml(
         '<table><tbody>'
@@ -1229,30 +1735,30 @@
     ]);
 
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
+      var tbody = div.nodes[0].nodes[0];
 
-    var tbody = div.nodes[0].nodes[0];
+      // 1 for the <tr template>, 2 * (1 tr)
+      expect(tbody.nodes.length, 3);
 
-    // 1 for the <tr template>, 2 * (1 tr)
-    expect(tbody.nodes.length, 3);
+      // 1 for the <td template>, 2 * (1 td)
+      expect(tbody.nodes[1].nodes.length, 3);
 
-    // 1 for the <td template>, 2 * (1 td)
-    expect(tbody.nodes[1].nodes.length, 3);
+      expect(tbody.nodes[1].nodes[1].text, '0');
+      expect(tbody.nodes[1].nodes[2].text, '1');
 
-    expect(tbody.nodes[1].nodes[1].text, '0');
-    expect(tbody.nodes[1].nodes[2].text, '1');
+      // 1 for the <td template>, 2 * (1 td)
+      expect(tbody.nodes[2].nodes.length, 3);
+      expect(tbody.nodes[2].nodes[1].text, '2');
+      expect(tbody.nodes[2].nodes[2].text, '3');
 
-    // 1 for the <td template>, 2 * (1 td)
-    expect(tbody.nodes[2].nodes.length, 3);
-    expect(tbody.nodes[2].nodes[1].text, '2');
-    expect(tbody.nodes[2].nodes[2].text, '3');
-
-    // Asset the 'class' binding is retained on the semantic template (just
-    // check the last one).
-    expect(tbody.nodes[2].nodes[2].attributes["class"], '3');
+      // Asset the 'class' binding is retained on the semantic template (just
+      // check the last one).
+      expect(tbody.nodes[2].nodes[2].attributes["class"], '3');
+    });
   });
 
-  observeTest('NestedIterateTable', () {
+  test('NestedIterateTable', () {
     var div = createTestHtml(
         '<table><tbody>'
           '<tr template repeat="{{}}">'
@@ -1266,30 +1772,31 @@
     ]);
 
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
 
-    var i = 1;
-    var tbody = div.nodes[0].nodes[0];
+      var i = 1;
+      var tbody = div.nodes[0].nodes[0];
 
-    // 1 for the <tr template>, 2 * (1 tr)
-    expect(tbody.nodes.length, 3);
+      // 1 for the <tr template>, 2 * (1 tr)
+      expect(tbody.nodes.length, 3);
 
-    // 1 for the <td template>, 2 * (1 td)
-    expect(tbody.nodes[1].nodes.length, 3);
-    expect(tbody.nodes[1].nodes[1].text, '0');
-    expect(tbody.nodes[1].nodes[2].text, '1');
+      // 1 for the <td template>, 2 * (1 td)
+      expect(tbody.nodes[1].nodes.length, 3);
+      expect(tbody.nodes[1].nodes[1].text, '0');
+      expect(tbody.nodes[1].nodes[2].text, '1');
 
-    // 1 for the <td template>, 2 * (1 td)
-    expect(tbody.nodes[2].nodes.length, 3);
-    expect(tbody.nodes[2].nodes[1].text, '2');
-    expect(tbody.nodes[2].nodes[2].text, '3');
+      // 1 for the <td template>, 2 * (1 td)
+      expect(tbody.nodes[2].nodes.length, 3);
+      expect(tbody.nodes[2].nodes[1].text, '2');
+      expect(tbody.nodes[2].nodes[2].text, '3');
 
-    // Asset the 'class' binding is retained on the semantic template (just
-    // check the last one).
-    expect(tbody.nodes[2].nodes[2].attributes['class'], '3');
+      // Asset the 'class' binding is retained on the semantic template (just
+      // check the last one).
+      expect(tbody.nodes[2].nodes[2].attributes['class'], '3');
+    });
   });
 
-  observeTest('NestedRepeatDeletionOfMultipleSubTemplates', () {
+  test('NestedRepeatDeletionOfMultipleSubTemplates', () {
     var div = createTestHtml(
         '<ul>'
           '<template repeat="{{}}" id=t1>'
@@ -1313,13 +1820,10 @@
     ]);
 
     recursivelySetTemplateModel(div, m);
-
-    performMicrotaskCheckpoint();
-    m.removeAt(0);
-    performMicrotaskCheckpoint();
+    return new Future(() => m.removeAt(0));
   });
 
-  observeTest('DeepNested', () {
+  test('DeepNested', () {
     var div = createTestHtml(
       '<template bind="{{a}}">'
         '<p>'
@@ -1337,34 +1841,36 @@
       }
     });
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes[1].tagName, 'P');
-    expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE');
-    expect(div.nodes[1].nodes[1].text, '42');
+    return new Future(() {
+      expect(div.nodes[1].tagName, 'P');
+      expect(div.nodes[1].nodes.first.tagName, 'TEMPLATE');
+      expect(div.nodes[1].nodes[1].text, '42');
+    });
   });
 
-  observeTest('TemplateContentRemoved', () {
+  test('TemplateContentRemoved', () {
     var div = createTestHtml('<template bind="{{}}">{{ }}</template>');
     var model = 42;
 
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-    expect(div.nodes[1].text, '42');
-    expect(div.nodes[0].text, '');
+    return new Future(() {
+      expect(div.nodes[1].text, '42');
+      expect(div.nodes[0].text, '');
+    });
   });
 
-  observeTest('TemplateContentRemovedEmptyArray', () {
+  test('TemplateContentRemovedEmptyArray', () {
     var div = createTestHtml('<template iterate>Remove me</template>');
     var model = toObservable([]);
 
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
-    expect(div.nodes[0].text, '');
+    return new Future(() {
+      expect(div.nodes.length, 1);
+      expect(div.nodes[0].text, '');
+    });
   });
 
-  observeTest('TemplateContentRemovedNested', () {
+  test('TemplateContentRemovedNested', () {
     var div = createTestHtml(
         '<template bind="{{}}">'
           '{{ a }}'
@@ -1378,35 +1884,36 @@
       'b': 2
     });
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes[0].text, '');
-    expect(div.nodes[1].text, '1');
-    expect(div.nodes[2].text, '');
-    expect(div.nodes[3].text, '2');
+    return new Future(() {
+      expect(div.nodes[0].text, '');
+      expect(div.nodes[1].text, '1');
+      expect(div.nodes[2].text, '');
+      expect(div.nodes[3].text, '2');
+    });
   });
 
-  observeTest('BindWithUndefinedModel', () {
+  test('BindWithUndefinedModel', () {
     var div = createTestHtml(
         '<template bind="{{}}" if="{{}}">{{ a }}</template>');
 
     var model = toObservable({'a': 42});
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-    expect(div.nodes[1].text, '42');
+    return new Future(() {
+      expect(div.nodes[1].text, '42');
 
-    model = null;
-    recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 1);
+      model = null;
+      recursivelySetTemplateModel(div, model);
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 1);
 
-    model = toObservable({'a': 42});
-    recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
-    expect(div.nodes[1].text, '42');
+      model = toObservable({'a': 42});
+      recursivelySetTemplateModel(div, model);
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes[1].text, '42');
+    });
   });
 
-  observeTest('BindNested', () {
+  test('BindNested', () {
     var div = createTestHtml(
         '<template bind="{{}}">'
           'Name: {{ name }}'
@@ -1425,24 +1932,24 @@
       }
     });
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
+      expect(div.nodes.length, 5);
+      expect(div.nodes[1].text, 'Name: Hermes');
+      expect(div.nodes[3].text, 'Wife: LaBarbara');
 
-    expect(div.nodes.length, 5);
-    expect(div.nodes[1].text, 'Name: Hermes');
-    expect(div.nodes[3].text, 'Wife: LaBarbara');
+      m['child'] = toObservable({'name': 'Dwight'});
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 6);
+      expect(div.nodes[5].text, 'Child: Dwight');
 
-    m['child'] = toObservable({'name': 'Dwight'});
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 6);
-    expect(div.nodes[5].text, 'Child: Dwight');
-
-    m.remove('wife');
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 5);
-    expect(div.nodes[4].text, 'Child: Dwight');
+      m.remove('wife');
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 5);
+      expect(div.nodes[4].text, 'Child: Dwight');
+    });
   });
 
-  observeTest('BindRecursive', () {
+  test('BindRecursive', () {
     var div = createTestHtml(
         '<template bind="{{}}" if="{{}}" id="t">'
           'Name: {{ name }}'
@@ -1456,24 +1963,24 @@
       }
     });
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
+      expect(div.nodes.length, 5);
+      expect(div.nodes[1].text, 'Name: Fry');
+      expect(div.nodes[3].text, 'Name: Bender');
 
-    expect(div.nodes.length, 5);
-    expect(div.nodes[1].text, 'Name: Fry');
-    expect(div.nodes[3].text, 'Name: Bender');
+      m['friend']['friend'] = toObservable({'name': 'Leela'});
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 7);
+      expect(div.nodes[5].text, 'Name: Leela');
 
-    m['friend']['friend'] = toObservable({'name': 'Leela'});
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 7);
-    expect(div.nodes[5].text, 'Name: Leela');
-
-    m['friend'] = toObservable({'name': 'Leela'});
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 5);
-    expect(div.nodes[3].text, 'Name: Leela');
+      m['friend'] = toObservable({'name': 'Leela'});
+    }).then(endOfMicrotask).then((_) {
+      expect(div.nodes.length, 5);
+      expect(div.nodes[3].text, 'Name: Leela');
+    });
   });
 
-  observeTest('Template - Self is terminator', () {
+  test('Template - Self is terminator', () {
     var div = createTestHtml(
         '<template repeat>{{ foo }}'
           '<template bind></template>'
@@ -1481,37 +1988,38 @@
 
     var m = toObservable([{ 'foo': 'bar' }]);
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    return new Future(() {
 
-    m.add(toObservable({ 'foo': 'baz' }));
-    recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+      m.add(toObservable({ 'foo': 'baz' }));
+      recursivelySetTemplateModel(div, m);
+    }).then(endOfMicrotask).then((_) {
 
-    expect(div.nodes.length, 5);
-    expect(div.nodes[1].text, 'bar');
-    expect(div.nodes[3].text, 'baz');
+      expect(div.nodes.length, 5);
+      expect(div.nodes[1].text, 'bar');
+      expect(div.nodes[3].text, 'baz');
+    });
   });
 
-  observeTest('Template - Same Contents, Different Array has no effect', () {
-    if (!MutationObserver.supported) return;
+  test('Template - Same Contents, Different Array has no effect', () {
+    if (!MutationObserver.supported) return null;
 
     var div = createTestHtml('<template repeat>{{ foo }}</template>');
 
     var m = toObservable([{ 'foo': 'bar' }, { 'foo': 'bat'}]);
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
+    var observer = new MutationObserver((x, y) {});
+    return new Future(() {
+      observer.observe(div, childList: true);
 
-    var observer = new MutationObserver((records, _) {});
-    observer.observe(div, childList: true);
-
-    var template = div.firstChild;
-    nodeBind(template).bind('repeat', toObservable(m.toList()), '');
-    performMicrotaskCheckpoint();
-    var records = observer.takeRecords();
-    expect(records.length, 0);
+      var template = div.firstChild;
+      templateBind(template).model = new ObservableList.from(m);
+    }).then(endOfMicrotask).then((_) {
+      var records = observer.takeRecords();
+      expect(records.length, 0);
+    });
   });
 
-  observeTest('RecursiveRef', () {
+  test('RecursiveRef', () {
     var div = createTestHtml(
         '<template bind>'
           '<template id=src>{{ foo }}</template>'
@@ -1520,54 +2028,13 @@
 
     var m = toObservable({'foo': 'bar'});
     recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes.length, 4);
-    expect(div.nodes[3].text, 'bar');
-  });
-
-  observeTest('ChangeFromBindToRepeat', () {
-    var div = createTestHtml(
-        '<template bind="{{a}}">'
-          '{{ length }}'
-        '</template>');
-    var template = div.nodes.first;
-
-    // Note: this test data is a little different from the JS version, because
-    // we allow binding to the "length" field of the Map in preference to
-    // binding keys.
-    var m = toObservable({
-      'a': [
-        [],
-        { 'b': [1,2,3,4] },
-        // Note: this will use the Map "length" property, not the "length" key.
-        {'length': 42, 'c': 123}
-      ]
+    return new Future(() {
+      expect(div.nodes.length, 4);
+      expect(div.nodes[3].text, 'bar');
     });
-    recursivelySetTemplateModel(div, m);
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes.length, 2);
-    expect(div.nodes[1].text, '3');
-
-    nodeBind(template)
-        ..unbind('bind')
-        ..bind('repeat', m, 'a');
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 4);
-    expect(div.nodes[1].text, '0');
-    expect(div.nodes[2].text, '1');
-    expect(div.nodes[3].text, '2');
-
-    nodeBind(template).unbind('repeat');
-    nodeBind(template).bind('bind', m, 'a.1.b');
-
-    performMicrotaskCheckpoint();
-    expect(div.nodes.length, 2);
-    expect(div.nodes[1].text, '4');
   });
 
-  observeTest('ChangeRefId', () {
+  test('ChangeRefId', () {
     var div = createTestHtml(
         '<template id="a">a:{{ }}</template>'
         '<template id="b">b:{{ }}</template>'
@@ -1576,22 +2043,22 @@
         '</template>');
     var model = toObservable([]);
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
+    return new Future(() {
+      expect(div.nodes.length, 3);
 
-    expect(div.nodes.length, 3);
+      document.getElementById('a').id = 'old-a';
+      document.getElementById('b').id = 'a';
 
-    document.getElementById('a').id = 'old-a';
-    document.getElementById('b').id = 'a';
+      model..add(1)..add(2);
+    }).then(endOfMicrotask).then((_) {
 
-    model..add(1)..add(2);
-    performMicrotaskCheckpoint();
-
-    expect(div.nodes.length, 7);
-    expect(div.nodes[4].text, 'b:1');
-    expect(div.nodes[6].text, 'b:2');
+      expect(div.nodes.length, 7);
+      expect(div.nodes[4].text, 'b:1');
+      expect(div.nodes[6].text, 'b:2');
+    });
   });
 
-  observeTest('Content', () {
+  test('Content', () {
     var div = createTestHtml(
         '<template><a></a></template>'
         '<template><b></b></template>');
@@ -1620,7 +2087,7 @@
     expect(contentB.nodes.first.tagName, 'B');
   });
 
-  observeTest('NestedContent', () {
+  test('NestedContent', () {
     var div = createTestHtml(
         '<template>'
         '<template></template>'
@@ -1634,46 +2101,44 @@
         templateBind(templateA).content.ownerDocument);
   });
 
-  observeTest('BindShadowDOM', () {
-    if (ShadowRoot.supported) {
-      var root = createShadowTestHtml(
-          '<template bind="{{}}">Hi {{ name }}</template>');
-      var model = toObservable({'name': 'Leela'});
-      recursivelySetTemplateModel(root, model);
-      performMicrotaskCheckpoint();
-      expect(root.nodes[1].text, 'Hi Leela');
-    }
+  test('BindShadowDOM', () {
+    if (!ShadowRoot.supported) return null;
+
+    var root = createShadowTestHtml(
+        '<template bind="{{}}">Hi {{ name }}</template>');
+    var model = toObservable({'name': 'Leela'});
+    recursivelySetTemplateModel(root, model);
+    return new Future(() => expect(root.nodes[1].text, 'Hi Leela'));
   });
 
   // Dart note: this test seems gone from JS. Keeping for posterity sake.
-  observeTest('BindShadowDOM createInstance', () {
-    if (ShadowRoot.supported) {
-      var model = toObservable({'name': 'Leela'});
-      var template = new Element.html('<template>Hi {{ name }}</template>');
-      var root = createShadowTestHtml('');
-      root.nodes.add(templateBind(template).createInstance(model));
+  test('BindShadowDOM createInstance', () {
+    if (!ShadowRoot.supported) return null;
 
-      performMicrotaskCheckpoint();
+    var model = toObservable({'name': 'Leela'});
+    var template = new Element.html('<template>Hi {{ name }}</template>');
+    var root = createShadowTestHtml('');
+    root.nodes.add(templateBind(template).createInstance(model));
+
+    return new Future(() {
       expect(root.text, 'Hi Leela');
 
       model['name'] = 'Fry';
-      performMicrotaskCheckpoint();
+    }).then(endOfMicrotask).then((_) {
       expect(root.text, 'Hi Fry');
-    }
+    });
   });
 
-  observeTest('BindShadowDOM Template Ref', () {
-    if (ShadowRoot.supported) {
-      var root = createShadowTestHtml(
-          '<template id=foo>Hi</template><template bind ref=foo></template>');
-      recursivelySetTemplateModel(root, toObservable({}));
-      performMicrotaskCheckpoint();
-      expect(root.nodes.length, 3);
-    }
+  test('BindShadowDOM Template Ref', () {
+    if (!ShadowRoot.supported) return null;
+    var root = createShadowTestHtml(
+        '<template id=foo>Hi</template><template bind ref=foo></template>');
+    recursivelySetTemplateModel(root, toObservable({}));
+    return new Future(() => expect(root.nodes.length, 3));
   });
 
-  // https://github.com/toolkitchen/mdv/issues/8
-  observeTest('UnbindingInNestedBind', () {
+  // https://github.com/Polymer/TemplateBinding/issues/8
+  test('UnbindingInNestedBind', () {
     var div = createTestHtml(
       '<template bind="{{outer}}" if="{{outer}}" syntax="testHelper">'
         '<template bind="{{inner}}" if="{{inner}}">'
@@ -1682,44 +2147,38 @@
       '</template>');
 
     var syntax = new UnbindingInNestedBindSyntax();
-    var model = toObservable({
-      'outer': {
-        'inner': {
-          'age': 42
-        }
-      }
-    });
+    var model = toObservable({'outer': {'inner': {'age': 42}}});
 
     recursivelySetTemplateModel(div, model, syntax);
 
-    performMicrotaskCheckpoint();
-    expect(syntax.count, 1);
+    return new Future(() {
+      expect(syntax.count, 1);
 
-    var inner = model['outer']['inner'];
-    model['outer'] = null;
+      var inner = model['outer']['inner'];
+      model['outer'] = null;
 
-    performMicrotaskCheckpoint();
-    expect(syntax.count, 1);
+    }).then(endOfMicrotask).then((_) {
+      expect(syntax.count, 1);
 
-    model['outer'] = toObservable({'inner': {'age': 2}});
-    syntax.expectedAge = 2;
+      model['outer'] = toObservable({'inner': {'age': 2}});
+      syntax.expectedAge = 2;
 
-    performMicrotaskCheckpoint();
-    expect(syntax.count, 2);
+    }).then(endOfMicrotask).then((_) {
+      expect(syntax.count, 2);
+    });
   });
 
   // https://github.com/toolkitchen/mdv/issues/8
-  observeTest('DontCreateInstancesForAbandonedIterators', () {
+  test('DontCreateInstancesForAbandonedIterators', () {
     var div = createTestHtml(
       '<template bind="{{}} {{}}">'
-        '<template bind="{{}}">Foo'
-        '</template>'
+        '<template bind="{{}}">Foo</template>'
       '</template>');
     recursivelySetTemplateModel(div, null);
-    performMicrotaskCheckpoint();
+    return nextMicrotask;
   });
 
-  observeTest('CreateInstance', () {
+  test('CreateInstance', () {
     var div = createTestHtml(
       '<template bind="{{a}}">'
         '<template bind="{{b}}">'
@@ -1735,11 +2194,35 @@
         templateBind(instance.nodes.first).ref);
 
     host.append(instance);
-    performMicrotaskCheckpoint();
-    expect(host.firstChild.nextNode.text, 'bar:replaced');
+    return new Future(() {
+      expect(host.firstChild.nextNode.text, 'bar:replaced');
+    });
   });
 
-  observeTest('Bootstrap', () {
+  test('Repeat - svg', () {
+    var div = createTestHtml(
+        '<svg width="400" height="110">'
+          '<template repeat>'
+            '<rect width="{{ width }}" height="{{ height }}" />'
+          '</template>'
+        '</svg>');
+
+    var model = toObservable([{ 'width': 10, 'height': 11 },
+                              { 'width': 20, 'height': 21 }]);
+    var svg = div.firstChild;
+    var template = svg.firstChild;
+    templateBind(template).model = model;
+
+    return new Future(() {
+      expect(svg.nodes.length, 3);
+      expect(svg.nodes[1].attributes['width'], '10');
+      expect(svg.nodes[1].attributes['height'], '11');
+      expect(svg.nodes[2].attributes['width'], '20');
+      expect(svg.nodes[2].attributes['height'], '21');
+    });
+  });
+
+  test('Bootstrap', () {
     var div = new DivElement();
     div.innerHtml =
       '<template>'
@@ -1773,7 +2256,7 @@
     expect(template3.content.nodes.first.text, 'Hello');
   });
 
-  observeTest('issue-285', () {
+  test('issue-285', () {
     var div = createTestHtml(
         '<template>'
           '<template bind if="{{show}}">'
@@ -1793,19 +2276,20 @@
     div.append(templateBind(template).createInstance(model,
         new Issue285Syntax()));
 
-    performMicrotaskCheckpoint();
-    expect(template.nextNode.nextNode.nextNode.text, '2');
-    model['show'] = false;
-    performMicrotaskCheckpoint();
-    model['show'] = true;
-    performMicrotaskCheckpoint();
-    expect(template.nextNode.nextNode.nextNode.text, '2');
+    return new Future(() {
+      expect(template.nextNode.nextNode.nextNode.text, '2');
+      model['show'] = false;
+    }).then(endOfMicrotask).then((_) {
+      model['show'] = true;
+    }).then(endOfMicrotask).then((_) {
+      expect(template.nextNode.nextNode.nextNode.text, '2');
+    });
   });
 
-  observeTest('issue-141', () {
+  test('issue-141', () {
     var div = createTestHtml(
-        '<template bind>' +
-          '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>' +
+        '<template bind>'
+          '<div foo="{{foo1}} {{foo2}}" bar="{{bar}}"></div>'
         '</template>');
 
     var model = toObservable({
@@ -1815,14 +2299,40 @@
     });
 
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
+    return new Future(() {
+      expect(div.lastChild.attributes['bar'], 'barValue');
+    });
+  });
 
-    expect(div.lastChild.attributes['bar'], 'barValue');
+  test('issue-18', () {
+    var delegate = new Issue18Syntax();
+
+    var div = createTestHtml(
+        '<template bind>'
+          '<div class="foo: {{ bar }}"></div>'
+        '</template>');
+
+    var model = toObservable({'bar': 2});
+
+    recursivelySetTemplateModel(div, model, delegate);
+
+    return new Future(() {
+      expect(div.lastChild.attributes['class'], 'foo: 2');
+    });
+  });
+
+  test('issue-152', () {
+    var div = createTestHtml('<template ref=notThere></template>');
+    var template = div.firstChild;
+
+    // if a ref cannot be located, a template will continue to use itself
+    // as the source of template instances.
+    expect(template, templateBind(template).ref);
   });
 }
 
 compatTests() {
-  observeTest('underbar bindings', () {
+  test('underbar bindings', () {
     var div = createTestHtml(
         '<template bind>'
           '<div _style="color: {{ color }};"></div>'
@@ -1839,19 +2349,19 @@
     });
 
     recursivelySetTemplateModel(div, model);
-    performMicrotaskCheckpoint();
+    return new Future(() {
+      var subDiv = div.firstChild.nextNode;
+      expect(subDiv.attributes['style'], 'color: red;');
 
-    var subDiv = div.firstChild.nextNode;
-    expect(subDiv.attributes['style'], 'color: red;');
+      var img = subDiv.nextNode;
+      expect(img.attributes['src'], 'pic.jpg');
 
-    var img = subDiv.nextNode;
-    expect(img.attributes['src'], 'pic.jpg');
+      var a = img.nextNode;
+      expect(a.attributes['href'], 'link.html');
 
-    var a = img.nextNode;
-    expect(a.attributes['href'], 'link.html');
-
-    var input = a.nextNode;
-    expect(input.value, '4');
+      var input = a.nextNode;
+      expect(input.value, '4');
+    });
   });
 }
 
@@ -1864,7 +2374,7 @@
 class TestBindingSyntax extends BindingDelegate {
   prepareBinding(String path, name, node) {
     if (path.trim() == 'replaceme') {
-      return (x, y) => new ObservableBox('replaced');
+      return (m, n, oneTime) => new PathObserver('replaced', '');
     }
     return null;
   }
@@ -1877,10 +2387,18 @@
   prepareBinding(path, name, node) {
     if (name != 'text' || path != 'age') return null;
 
-    return (model, node) {
+    return (model, _, oneTime) {
       expect(model['age'], expectedAge);
       count++;
-      return model;
+      return new PathObserver(model, path);
     };
   }
 }
+
+class Issue18Syntax extends BindingDelegate {
+  prepareBinding(path, name, node) {
+    if (name != 'class') return null;
+
+    return (model, _, oneTime) => new PathObserver(model, path);
+  }
+}
diff --git a/pkg/template_binding/test/utils.dart b/pkg/template_binding/test/utils.dart
index 92d63e4..11f7668 100644
--- a/pkg/template_binding/test/utils.dart
+++ b/pkg/template_binding/test/utils.dart
@@ -4,13 +4,23 @@
 
 library template_binding.test.utils;
 
+import 'dart:async';
 import 'dart:html';
 import 'package:observe/observe.dart';
 import 'package:template_binding/template_binding.dart';
-import 'package:unittest/unittest.dart';
+export 'package:observe/src/dirty_check.dart' show dirtyCheckZone;
 
-import 'package:observe/src/microtask.dart';
-export 'package:observe/src/microtask.dart';
+/// A small method to help readability. Used to cause the next "then" in a chain
+/// to happen in the next microtask:
+///
+///     future.then(newMicrotask).then(...)
+endOfMicrotask(_) => new Future.value();
+
+/// A small method to help readability. Used to cause the next "then" in a chain
+/// to happen in the next microtask, after a timer:
+///
+///     future.then(nextMicrotask).then(...)
+nextMicrotask(_) => new Future(() {});
 
 final bool parserHasNativeTemplate = () {
   var div = new DivElement()..innerHtml = '<table><template>';
@@ -57,10 +67,6 @@
   }
 }
 
-observeTest(name, testCase) => test(name, wrapMicrotask(testCase));
-
-solo_observeTest(name, testCase) => solo_test(name, wrapMicrotask(testCase));
-
 DivElement testDiv;
 
 createTestHtml(s) {
@@ -68,7 +74,7 @@
   div.setInnerHtml(s, treeSanitizer: new NullTreeSanitizer());
   testDiv.append(div);
 
-  for (var node in div.queryAll('*')) {
+  for (var node in div.querySelectorAll('*')) {
     if (isSemanticTemplate(node)) TemplateBindExtension.decorate(node);
   }
 
diff --git a/pkg/unittest/CHANGELOG.md b/pkg/unittest/CHANGELOG.md
new file mode 100644
index 0000000..9392db2
--- /dev/null
+++ b/pkg/unittest/CHANGELOG.md
@@ -0,0 +1,19 @@
+# Changelog - unittest
+
+##0.10.0-dev
+
+* Each test is run in a seperate `Zone`. This ensures that any exceptions that
+occur is async operations are reported back to the source test case.
+* **DEPRECATED** `guardAsync`, `protectAsync0`, `protectAsync1`,
+and `protectAsync2`
+    * Running each test in a `Zone` addresses the need for these methods.
+* `TestCase`:
+    * Removed properties: `setUp`, `tearDown`, `testFunction`
+    * `enabled` is now get-only
+    * Removed methods: `pass`, `fail`, `error`
+* `interactive_html_config.dart` has been removed.
+* `runTests`, `tearDown`, `setUp`, `test`, `group`, `solo_test`, and
+  `solo_group` now throw a `StateError` if called while tests are running.
+* `rerunTests` has been removed.
+
+##0.9.3 - 2014-01-13
diff --git a/pkg/unittest/lib/html_config.dart b/pkg/unittest/lib/html_config.dart
index dd760bd..ef23d52 100644
--- a/pkg/unittest/lib/html_config.dart
+++ b/pkg/unittest/lib/html_config.dart
@@ -134,7 +134,7 @@
   void onInit() {
     // For Dart internal tests, we want to turn off stack frame
     // filtering, which we do with this meta-header.
-    var meta = query('meta[name="dart.unittest"]');
+    var meta = querySelector('meta[name="dart.unittest"]');
     filterStacks = meta == null ? true :
         !meta.content.contains('full-stack-traces');
     _installHandlers();
diff --git a/pkg/unittest/lib/html_enhanced_config.dart b/pkg/unittest/lib/html_enhanced_config.dart
index f303f24..d434663 100644
--- a/pkg/unittest/lib/html_enhanced_config.dart
+++ b/pkg/unittest/lib/html_enhanced_config.dart
@@ -67,7 +67,7 @@
     //initialize and load CSS
     final String _CSSID = '_unittestcss_';
 
-    var cssElement = document.head.query('#${_CSSID}');
+    var cssElement = document.head.querySelector('#${_CSSID}');
     if (cssElement == null) {
       cssElement = new StyleElement();
       cssElement.id = _CSSID;
@@ -134,9 +134,9 @@
        """));
 
       // handle the click event for the collapse all button
-      te.query('#btnCollapseAll').onClick.listen((_){
+      te.querySelector('#btnCollapseAll').onClick.listen((_){
         document
-          .queryAll('.unittest-row')
+          .querySelectorAll('.unittest-row')
           .forEach((el) => el.attributes['class'] = el.attributes['class']
               .replaceAll('unittest-row ', 'unittest-row-hidden '));
       });
@@ -207,16 +207,17 @@
             </div>"""));
 
           // 'safeGroup' could be empty
-          var grp = (safeGroup == '') ? null : te.query('#${safeGroup}');
+          var grp = (safeGroup == '') ?
+              null : te.querySelector('#${safeGroup}');
           if (grp != null) {
             grp.onClick.listen((_) {
-              var row = document.query('.unittest-row-${safeGroup}');
+              var row = document.querySelector('.unittest-row-${safeGroup}');
               if (row.attributes['class'].contains('unittest-row ')){
-                document.queryAll('.unittest-row-${safeGroup}').forEach(
+                document.querySelectorAll('.unittest-row-${safeGroup}').forEach(
                     (e) => e.attributes['class'] =  e.attributes['class']
                         .replaceAll('unittest-row ', 'unittest-row-hidden '));
               }else{
-                document.queryAll('.unittest-row-${safeGroup}').forEach(
+                document.querySelectorAll('.unittest-row-${safeGroup}').forEach(
                     (e) => e.attributes['class'] = e.attributes['class']
                         .replaceAll('unittest-row-hidden', 'unittest-row'));
               }
diff --git a/pkg/unittest/lib/interactive_html_config.dart b/pkg/unittest/lib/interactive_html_config.dart
deleted file mode 100644
index 46be199..0000000
--- a/pkg/unittest/lib/interactive_html_config.dart
+++ /dev/null
@@ -1,709 +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.
-
-/**
- * This configuration can be used to rerun selected tests, as well
- * as see diagnostic output from tests. It runs each test in its own
- * IFrame, so the configuration consists of two parts - a 'parent'
- * config that manages all the tests, and a 'child' config for the
- * IFrame that runs the individual tests.
- *
- * Note: this unit test configuration will not work with the debugger (the tests
- * are executed in a separate IFrame).
- */
-library unittest.interactive_html_config;
-
-// TODO(gram) - add options for: remove IFrame on done/keep
-// IFrame for failed tests/keep IFrame for all tests.
-
-import 'dart:html';
-import 'dart:async';
-import 'dart:convert';
-
-import 'package:stack_trace/stack_trace.dart';
-
-import 'unittest.dart';
-
-/** The messages exchanged between parent and child. */
-class _Message {
-  static const START = 'start';
-  static const LOG = 'log';
-  static const STACK = 'stack';
-  static const PASS = 'pass';
-  static const FAIL = 'fail';
-  static const ERROR = 'error';
-  static const _PREFIX = 'TestMsg:';
-
-  final String messageType;
-  final int elapsed;
-  final String body;
-
-  static String text(String messageType,
-                     [int elapsed = 0, String body = '']) =>
-      '$_PREFIX$messageType $elapsed $body';
-
-  _Message(this.messageType, [this.elapsed = 0, this.body = '']);
-
-  factory _Message.fromString(String msg) {
-    if (!msg.startsWith(_PREFIX)) {
-      return null;
-    }
-    int idx = msg.indexOf(' ', _PREFIX.length);
-    var messageType = msg.substring(_PREFIX.length, idx);
-    ++idx;
-    int idx2 = msg.indexOf(' ', idx);
-    var elapsed = int.parse(msg.substring(idx, idx2));
-    ++idx2;
-    var body = msg.substring(idx2);
-
-    return new _Message(messageType, elapsed, body);
-  }
-
-  String toString() => text(messageType, elapsed, body);
-}
-
-
-class HtmlConfiguration extends SimpleConfiguration {
-  StreamSubscription _errorSubscription;
-
-  void _installErrorHandler() {
-    if (_errorSubscription == null) {
-      _errorSubscription = window.onError.listen((e) {
-        handleExternalError(e, '(DOM callback has errors)');
-      });
-    }
-  }
-
-  void _uninstallErrorHandler() {
-    if (_errorSubscription != null) {
-      _errorSubscription.cancel();
-      _errorSubscription = null;
-    }
-  }
-}
-
-/**
- * The child configuration that is used to run individual tests in
- * an IFrame and post the results back to the parent. In principle
- * this can run more than one test in the IFrame but currently only
- * one is used.
- */
-class ChildInteractiveHtmlConfiguration extends HtmlConfiguration {
-
-  /** The window to which results must be posted. */
-  WindowBase _parentWindow;
-
-  /** The time at which tests start. */
-  final Map<int, DateTime> _testStarts;
-
-  ChildInteractiveHtmlConfiguration() :
-      _testStarts = new Map<int,DateTime>();
-
-  /** Don't start running tests automatically. */
-  get autoStart => false;
-
-  void onInit() {
-    _installErrorHandler();
-
-    /**
-     *  The parent posts a 'start' message to kick things off,
-     *  which is handled by this handler. It saves the parent
-     *  window, gets the test ID from the query parameter in the
-     *  IFrame URL, sets that as a solo test and starts test execution.
-     */
-    window.onMessage.listen((MessageEvent e) {
-      // Get the result, do any logging, then do a pass/fail.
-      var m = new _Message.fromString(e.data);
-      if (m != null && m.messageType == _Message.START) {
-        _parentWindow = e.source;
-        String search = window.location.search;
-        int pos = search.indexOf('t=');
-        String ids = search.substring(pos + 2);
-        int id = int.parse(ids);
-        setSoloTest(id);
-        runTests();
-      }
-    });
-  }
-
-  void onStart() {
-    _installErrorHandler();
-  }
-
-  /** Record the start time of the test. */
-  void onTestStart(TestCase testCase) {
-    super.onTestStart(testCase);
-    _testStarts[testCase.id] = new DateTime.now();
-  }
-
-  /**
-   * Tests can call [logMessage] for diagnostic output. These log
-   * messages in turn get passed to this method, which adds
-   * a timestamp and posts them back to the parent window.
-   */
-  void onLogMessage(TestCase testCase, String message) {
-    int elapsed;
-    if (testCase == null) {
-      elapsed = -1;
-    } else {
-      DateTime end = new DateTime.now();
-      elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
-    }
-    _parentWindow.postMessage(
-      _Message.text(_Message.LOG, elapsed, message).toString(), '*');
-  }
-
-  /**
-   * Get the elapsed time for the test, and post the test result back to the
-   * parent window. If the test failed due to an exception the stack is posted
-   * back too (before the test result).
-   */
-  void onTestResult(TestCase testCase) {
-    super.onTestResult(testCase);
-    DateTime end = new DateTime.now();
-    int elapsed = end.difference(_testStarts[testCase.id]).inMilliseconds;
-    if (testCase.stackTrace != null) {
-      var message = JSON.encode(testCase.stackTrace.frames.map((frame) {
-        return <String, dynamic> {
-          "uri": frame.uri.toString(),
-          "line": frame.line,
-          "column": frame.column,
-          "member": frame.member
-        };
-      }).toList());
-      _parentWindow.postMessage(
-          _Message.text(_Message.STACK, elapsed, message), '*');
-    }
-    _parentWindow.postMessage(
-        _Message.text(testCase.result, elapsed, testCase.message), '*');
-  }
-  void onSummary(int passed, int failed, int errors, List<TestCase> results,
-      String uncaughtError) {
-  }
-
-  void onDone(bool success) {
-    _uninstallErrorHandler();
-  }
-}
-
-/**
- * The parent configuration runs in the top-level window; it wraps the tests
- * in new functions that create child IFrames and run the real tests.
- */
-class ParentInteractiveHtmlConfiguration extends HtmlConfiguration {
-  final Map<int, DateTime> _testStarts;
-
-
-  /** The stack that was posted back from the child, if any. */
-  Trace _stack;
-
-  int _testTime;
-  /**
-   * Whether or not we have already wrapped the TestCase test functions
-   * in new closures that instead create an IFrame and get it to run the
-   * test.
-   */
-  bool _doneWrap = false;
-
-  StreamSubscription _messageSubscription;
-
-  ParentInteractiveHtmlConfiguration() :
-      _testStarts = new Map<int,DateTime>();
-
-  // We need to block until the test is done, so we make a
-  // dummy async callback that we will use to flag completion.
-  Function _completeTest = null;
-
-  Function _wrapTest(TestCase testCase) {
-    String baseUrl = window.location.toString();
-    String url = '${baseUrl}?t=${testCase.id}';
-    return () {
-      // Rebuild the child IFrame.
-      Element childDiv = document.query('#child');
-      childDiv.nodes.clear();
-      IFrameElement child = new Element.html("""
-          <iframe id='childFrame${testCase.id}' src='$url' style='display:none'>
-          </iframe>""");
-      childDiv.nodes.add(child);
-      _completeTest = expectAsync0((){ });
-      // Kick off the test when the IFrame is loaded.
-      child.onLoad.listen((e) {
-        child.contentWindow.postMessage(_Message.text(_Message.START), '*');
-      });
-    };
-  }
-
-  void _handleMessage(MessageEvent e) {
-    // Get the result, do any logging, then do a pass/fail.
-    var msg = new _Message.fromString(e.data);
-
-    if (msg == null) {
-      return;
-    }
-    if (msg.messageType == _Message.LOG) {
-      logMessage(e.data);
-    } else if (msg.messageType == _Message.STACK) {
-      _stack = new Trace(JSON.decode(msg.body).map((frame) {
-        return new Frame(
-            Uri.parse(frame['uri']),
-            frame['line'],
-            frame['column'],
-            frame['member']);
-      }));
-    } else {
-      _testTime = msg.elapsed;
-      logMessage(_Message.text(_Message.LOG, _testTime, 'Complete'));
-      if (msg.messageType == _Message.PASS) {
-        currentTestCase.pass();
-      } else if (msg.messageType == _Message.FAIL) {
-        currentTestCase.fail(msg.body, _stack);
-      } else if (msg.messageType == _Message.ERROR) {
-        currentTestCase.error(msg.body, _stack);
-      }
-      _completeTest();
-    }
-  }
-
-  void onInit() {
-    _installErrorHandler();
-    document.query('#group-divs').innerHtml = "";
-  }
-
-  void onStart() {
-    _installErrorHandler();
-    if (!_doneWrap) {
-      _doneWrap = true;
-      for (int i = 0; i < testCases.length; i++) {
-        testCases[i].testFunction = _wrapTest(testCases[i]);
-        testCases[i].setUp = null;
-        testCases[i].tearDown = null;
-      }
-    }
-    assert(_messageSubscription == null);
-    _messageSubscription = window.onMessage.listen(_handleMessage);
-  }
-
-  static final _notAlphaNumeric = new RegExp('[^a-z0-9A-Z]');
-
-  String _stringToDomId(String s) {
-    if (s.length == 0) {
-      return '-None-';
-    }
-    return s.trim().replaceAll(_notAlphaNumeric, '-');
-  }
-
-  // Used for DOM element IDs for tests result list entries.
-  static const _testIdPrefix = 'test-';
-  // Used for DOM element IDs for test log message lists.
-  static const _actionIdPrefix = 'act-';
-  // Used for DOM element IDs for test checkboxes.
-  static const _selectedIdPrefix = 'selected-';
-
-  void onTestStart(TestCase testCase) {
-    var id = testCase.id;
-    _testStarts[testCase.id] = new DateTime.now();
-    super.onTestStart(testCase);
-    _stack = null;
-    // Convert the group name to a DOM id.
-    String groupId = _stringToDomId(testCase.currentGroup);
-    // Get the div for the group. If it doesn't exist,
-    // create it.
-    var groupDiv = document.query('#$groupId');
-    if (groupDiv == null) {
-      groupDiv = new Element.html("""
-          <div class='test-describe' id='$groupId'>
-            <h2>
-              <input type='checkbox' checked='true' class='groupselect'>
-              Group: ${testCase.currentGroup}
-            </h2>
-            <ul class='tests'>
-            </ul>
-          </div>""");
-      document.query('#group-divs').nodes.add(groupDiv);
-      groupDiv.query('.groupselect').onClick.listen((e) {
-        var parent = document.query('#$groupId');
-        InputElement cb = parent.query('.groupselect');
-        var state = cb.checked;
-        var tests = parent.query('.tests');
-        for (Element t in tests.children) {
-          cb = t.query('.testselect') as InputElement;
-          cb.checked = state;
-          var testId = int.parse(t.id.substring(_testIdPrefix.length));
-          if (state) {
-            enableTest(testId);
-          } else {
-            disableTest(testId);
-          }
-        }
-      });
-    }
-    var list = groupDiv.query('.tests');
-    var testItem = list.query('#$_testIdPrefix$id');
-    if (testItem == null) {
-      // Create the li element for the test.
-      testItem = new Element.html("""
-          <li id='$_testIdPrefix$id' class='test-it status-pending'>
-            <div class='test-info'>
-              <p class='test-title'>
-                <input type='checkbox' checked='true' class='testselect'
-                    id='$_selectedIdPrefix$id'>
-                <span class='test-label'>
-                <span class='timer-result test-timer-result'></span>
-                <span class='test-name closed'>${testCase.description}</span>
-                </span>
-              </p>
-            </div>
-            <div class='scrollpane'>
-              <ol class='test-actions' id='$_actionIdPrefix$id'></ol>
-            </div>
-          </li>""");
-      list.nodes.add(testItem);
-      testItem.query('#$_selectedIdPrefix$id').onChange.listen((e) {
-        InputElement cb = testItem.query('#$_selectedIdPrefix$id');
-        testCase.enabled = cb.checked;
-      });
-      testItem.query('.test-label').onClick.listen((e) {
-        var _testItem = document.query('#$_testIdPrefix$id');
-        var _actions = _testItem.query('#$_actionIdPrefix$id');
-        var _label = _testItem.query('.test-name');
-        if (_actions.style.display == 'none') {
-          _actions.style.display = 'table';
-          _label.classes.remove('closed');
-          _label.classes.add('open');
-        } else {
-          _actions.style.display = 'none';
-          _label.classes.remove('open');
-          _label.classes.add('closed');
-        }
-      });
-    } else { // Reset the test element.
-      testItem.classes.clear();
-      testItem.classes.add('test-it');
-      testItem.classes.add('status-pending');
-      testItem.query('#$_actionIdPrefix$id').innerHtml = '';
-    }
-  }
-
-  // Actually test logging is handled by the child, then posted
-  // back to the parent. So here we know that the [message] argument
-  // is in the format used by [_Message].
-  void onLogMessage(TestCase testCase, String message) {
-    var msg = new _Message.fromString(message);
-    if (msg.elapsed < 0) { // No associated test case.
-      document.query('#otherlogs').nodes.add(
-          new Element.html('<p>${msg.body}</p>'));
-    } else {
-      var actions = document.query('#$_testIdPrefix${testCase.id}').
-          query('.test-actions');
-      String elapsedText = msg.elapsed >= 0 ? "${msg.elapsed}ms" : "";
-      actions.nodes.add(new Element.html(
-          "<li style='list-style-stype:none>"
-              "<div class='timer-result'>${elapsedText}</div>"
-              "<div class='test-title'>${msg.body}</div>"
-          "</li>"));
-    }
-  }
-
-  void onTestResult(TestCase testCase) {
-    if (!testCase.enabled) return;
-    super.onTestResult(testCase);
-    if (testCase.message != '') {
-      onLogMessage(testCase,
-          _Message.text(_Message.LOG, -1, testCase.message));
-    }
-    int id = testCase.id;
-    var testItem = document.query('#$_testIdPrefix$id');
-    var timeSpan = testItem.query('.test-timer-result');
-    timeSpan.text = '${_testTime}ms';
-    // Convert status into what we need for our CSS.
-    String result = 'status-error';
-    if (testCase.result == 'pass') {
-      result = 'status-success';
-    } else if (testCase.result == 'fail') {
-      result = 'status-failure';
-    }
-    testItem.classes.remove('status-pending');
-    testItem.classes.add(result);
-    // hide the actions
-    var actions = testItem.query('.test-actions');
-    for (Element e in actions.nodes) {
-      e.classes.add(result);
-    }
-    actions.style.display = 'none';
-  }
-
-  void onSummary(int passed, int failed, int errors, List<TestCase> results,
-      String uncaughtError) {
-  }
-
-  void onDone(bool success) {
-    assert(_messageSubscription != null);
-    _messageSubscription.cancel();
-    _messageSubscription = null;
-    _uninstallErrorHandler();
-    document.query('#busy').style.display = 'none';
-    InputElement startButton = document.query('#start');
-    startButton.disabled = false;
-  }
-}
-
-/**
- * Add the divs to the DOM if they are not present. We have a 'controls'
- * div for control, 'specs' div with test results, a 'busy' div for the
- * animated GIF used to indicate tests are running, and a 'child' div to
- * hold the iframe for the test.
- */
-void _prepareDom() {
-  if (document.query('#control') == null) {
-    // Use this as an opportunity for adding the CSS too.
-    // I wanted to avoid having to include a css element explicitly
-    // in the main html file. I considered moving all the styles
-    // inline as attributes but that started getting very messy,
-    // so we do it this way.
-    document.body.nodes.add(new Element.html("<style>$_CSS</style>"));
-    document.body.nodes.add(new Element.html(
-        "<div id='control'>"
-            "<input id='start' disabled='true' type='button' value='Run'>"
-        "</div>"));
-    document.query('#start').onClick.listen((e) {
-      InputElement startButton = document.query('#start');
-      startButton.disabled = true;
-      rerunTests();
-    });
-  }
-  if (document.query('#otherlogs') == null) {
-    document.body.nodes.add(new Element.html(
-        "<div id='otherlogs'></div>"));
-  }
-  if (document.query('#specs') == null) {
-    document.body.nodes.add(new Element.html(
-        "<div id='specs'><div id='group-divs'></div></div>"));
-  }
-  if (document.query('#busy') == null) {
-    document.body.nodes.add(new Element.html(
-        "<div id='busy' style='display:none'><img src='googleballs.gif'>"
-        "</img></div>"));
-  }
-  if (document.query('#child') == null) {
-    document.body.nodes.add(new Element.html("<div id='child'></div>"));
-  }
-}
-
-/**
- * Allocate a Configuration. We allocate either a parent or child, depending on
- * whether the URL has a search part.
- *
- * Note: this unit test configuration will not work with the debugger (the tests
- * are executed in a separate IFrame).
- */
-void useInteractiveHtmlConfiguration() {
-  if (window.location.search == '') { // This is the parent.
-    _prepareDom();
-    unittestConfiguration = _singletonParent;
-  } else {
-    unittestConfiguration = _singletonChild;
-  }
-}
-
-final _singletonParent = new ParentInteractiveHtmlConfiguration();
-final _singletonChild = new ChildInteractiveHtmlConfiguration();
-
-const String _CSS = """
-body {
-font-family: Arial, sans-serif;
-margin: 0;
-font-size: 14px;
-}
-
-#application h2,
-#specs h2 {
-margin: 0;
-padding: 0.5em;
-font-size: 1.1em;
-}
-
-#header,
-#application,
-.test-info,
-.test-actions li {
-overflow: hidden;
-}
-
-#application {
-margin: 10px;
-}
-
-#application iframe {
-width: 100%;
-height: 758px;
-}
-
-#application iframe {
-border: none;
-}
-
-#specs {
-padding-top: 50px
-}
-
-.test-describe h2 {
-border-top: 2px solid #BABAD1;
-background-color: #efefef;
-}
-
-.tests,
-.test-it ol,
-.status-display {
-margin: 0;
-padding: 0;
-}
-
-.test-info {
-margin-left: 1em;
-margin-top: 0.5em;
-border-radius: 8px 0 0 8px;
--webkit-border-radius: 8px 0 0 8px;
--moz-border-radius: 8px 0 0 8px;
-cursor: pointer;
-}
-
-.test-info:hover .test-name {
-text-decoration: underline;
-}
-
-.test-info .closed:before {
-content: '\\25b8\\00A0';
-}
-
-.test-info .open:before {
-content: '\\25be\\00A0';
-font-weight: bold;
-}
-
-.test-it ol {
-margin-left: 2.5em;
-}
-
-.status-display,
-.status-display li {
-float: right;
-}
-
-.status-display li {
-padding: 5px 10px;
-}
-
-.timer-result,
-.test-title {
-display: inline-block;
-margin: 0;
-padding: 4px;
-}
-
-.test-actions .test-title,
-.test-actions .test-result {
-display: table-cell;
-padding-left: 0.5em;
-padding-right: 0.5em;
-}
-
-.test-it {
-list-style-type: none;
-}
-
-.test-actions {
-display: table;
-}
-
-.test-actions li {
-display: table-row;
-}
-
-.timer-result {
-width: 4em;
-padding: 0 10px;
-text-align: right;
-font-family: monospace;
-}
-
-.test-it pre,
-.test-actions pre {
-clear: left;
-color: black;
-margin-left: 6em;
-}
-
-.test-describe {
-margin: 5px 5px 10px 2em;
-border-left: 1px solid #BABAD1;
-border-right: 1px solid #BABAD1;
-border-bottom: 1px solid #BABAD1;
-padding-bottom: 0.5em;
-}
-
-.test-actions .status-pending .test-title:before {
-content: \\'\\\\00bb\\\\00A0\\';
-}
-
-.scrollpane {
- max-height: 20em;
- overflow: auto;
-}
-
-#busy {
-display: block;
-}
-/** Colors */
-
-#header {
-background-color: #F2C200;
-}
-
-#application {
-border: 1px solid #BABAD1;
-}
-
-.status-pending .test-info {
-background-color: #F9EEBC;
-}
-
-.status-success .test-info {
-background-color: #B1D7A1;
-}
-
-.status-failure .test-info {
-background-color: #FF8286;
-}
-
-.status-error .test-info {
-background-color: black;
-color: white;
-}
-
-.test-actions .status-success .test-title {
-color: #30B30A;
-}
-
-.test-actions .status-failure .test-title {
-color: #DF0000;
-}
-
-.test-actions .status-error .test-title {
-color: black;
-}
-
-.test-actions .timer-result {
-color: #888;
-}
-
-ul, menu, dir {
-display: block;
-list-style-type: disc;
--webkit-margin-before: 1em;
--webkit-margin-after: 1em;
--webkit-margin-start: 0px;
--webkit-margin-end: 0px;
--webkit-padding-start: 40px;
-}
-""";
diff --git a/pkg/unittest/lib/src/group_context.dart b/pkg/unittest/lib/src/group_context.dart
new file mode 100644
index 0000000..668fb47
--- /dev/null
+++ b/pkg/unittest/lib/src/group_context.dart
@@ -0,0 +1,67 @@
+part of unittest;
+
+/**
+ * Setup and teardown functions for a group and its parents, the latter
+ * for chaining.
+ */
+class _GroupContext {
+  final _GroupContext parent;
+
+  /** Description text of the current test group. */
+  final String _name;
+
+  /** Setup function called before each test in a group. */
+  Function _testSetup;
+
+  get testSetup => _testSetup;
+
+  get parentSetup => (parent == null) ? null : parent.testSetup;
+
+  set testSetup(Function setup) {
+    var preSetup = parentSetup;
+    if (preSetup == null) {
+      _testSetup = setup;
+    } else {
+      _testSetup = () {
+        var f = preSetup();
+        if (f is Future) {
+          return f.then((_) => setup());
+        } else {
+          return setup();
+        }
+      };
+    }
+  }
+
+  /** Teardown function called after each test in a group. */
+  Function _testTeardown;
+
+  get testTeardown => _testTeardown;
+
+  get parentTeardown => (parent == null) ? null : parent.testTeardown;
+
+  set testTeardown(Function teardown) {
+    var postTeardown = parentTeardown;
+    if (postTeardown == null) {
+      _testTeardown = teardown;
+    } else {
+      _testTeardown = () {
+        var f = teardown();
+        if (f is Future) {
+          return f.then((_) => postTeardown());
+        } else {
+          return postTeardown();
+        }
+      };
+    }
+  }
+
+  String get fullName => (parent == null || parent == _rootContext)
+      ? _name
+      : "${parent.fullName}$groupSep$_name";
+
+  _GroupContext([this.parent, this._name = '']) {
+    _testSetup = parentSetup;
+    _testTeardown = parentTeardown;
+  }
+}
diff --git a/pkg/unittest/lib/src/spread_args_helper.dart b/pkg/unittest/lib/src/spread_args_helper.dart
new file mode 100644
index 0000000..41411b9
--- /dev/null
+++ b/pkg/unittest/lib/src/spread_args_helper.dart
@@ -0,0 +1,133 @@
+part of unittest;
+
+/** Simulates spread arguments using named arguments. */
+// TODO(sigmund): remove this class and simply use a closure with named
+// arguments (if still applicable).
+class _SpreadArgsHelper {
+  final Function callback;
+  final int minExpectedCalls;
+  final int maxExpectedCalls;
+  final Function isDone;
+  final String id;
+  int actualCalls = 0;
+  final TestCase testCase;
+  bool complete;
+
+  _SpreadArgsHelper(Function callback, int minExpected, int maxExpected,
+      Function isDone, String id)
+      : this.callback = callback,
+        minExpectedCalls = minExpected,
+        maxExpectedCalls = (maxExpected == 0 && minExpected > 0)
+            ? minExpected
+            : maxExpected,
+        this.isDone = isDone,
+        this.testCase = currentTestCase,
+        this.id = _makeCallbackId(id, callback) {
+    ensureInitialized();
+    if (testCase == null) {
+      throw new StateError("No valid test. Did you forget to run your test "
+          "inside a call to test()?");
+    }
+
+    if (isDone != null || minExpected > 0) {
+      testCase._callbackFunctionsOutstanding++;
+      complete = false;
+    } else {
+      complete = true;
+    }
+  }
+
+  static String _makeCallbackId(String id, Function callback) {
+    // Try to create a reasonable id.
+    if (id != null) {
+      return "$id ";
+    } else {
+      // If the callback is not an anonymous closure, try to get the
+      // name.
+      var fname = callback.toString();
+      var prefix = "Function '";
+      var pos = fname.indexOf(prefix);
+      if (pos > 0) {
+        pos += prefix.length;
+        var epos = fname.indexOf("'", pos);
+        if (epos > 0) {
+          return "${fname.substring(pos, epos)} ";
+        }
+      }
+    }
+    return '';
+  }
+
+  bool shouldCallBack() {
+    ++actualCalls;
+    if (testCase.isComplete) {
+      // Don't run if the test is done. We don't throw here as this is not
+      // the current test, but we do mark the old test as having an error
+      // if it previously passed.
+      if (testCase.result == PASS) {
+        testCase._error(
+            'Callback ${id}called ($actualCalls) after test case '
+            '${testCase.description} has already been marked as '
+            '${testCase.result}.');
+      }
+      return false;
+    } else if (maxExpectedCalls >= 0 && actualCalls > maxExpectedCalls) {
+      throw new TestFailure('Callback ${id}called more times than expected '
+                            '($maxExpectedCalls).');
+    }
+    return true;
+  }
+
+  void after() {
+    if (!complete) {
+      if (minExpectedCalls > 0 && actualCalls < minExpectedCalls) return;
+      if (isDone != null && !isDone()) return;
+
+      // Mark this callback as complete and remove it from the testcase
+      // oustanding callback count; if that hits zero the testcase is done.
+      complete = true;
+      testCase._markCallbackComplete();
+    }
+  }
+
+  invoke0() {
+    return _guardAsync(
+        () {
+          if (shouldCallBack()) {
+            return callback();
+          }
+        },
+        after, testCase);
+  }
+
+  invoke1(arg1) {
+    return _guardAsync(
+        () {
+          if (shouldCallBack()) {
+            return callback(arg1);
+          }
+        },
+        after, testCase);
+  }
+
+  invoke2(arg1, arg2) {
+    return _guardAsync(
+        () {
+          if (shouldCallBack()) {
+            return callback(arg1, arg2);
+          }
+        },
+        after, testCase);
+  }
+
+  _guardAsync(Function tryBody, Function finallyBody, TestCase testCase) {
+    assert(testCase != null);
+    try {
+      return tryBody();
+    } catch (e, trace) {
+      _registerException(testCase, e, trace);
+    } finally {
+      if (finallyBody != null) finallyBody();
+    }
+  }
+}
diff --git a/pkg/unittest/lib/src/test_case.dart b/pkg/unittest/lib/src/test_case.dart
index 95068bd..d4802ea 100644
--- a/pkg/unittest/lib/src/test_case.dart
+++ b/pkg/unittest/lib/src/test_case.dart
@@ -17,13 +17,13 @@
   final String description;
 
   /** The setup function to call before the test, if any. */
-  Function setUp;
+  final Function _setUp;
 
   /** The teardown function to call after the test, if any. */
-  Function tearDown;
+  final Function _tearDown;
 
   /** The body of the test case. */
-  TestFunction testFunction;
+  final TestFunction _testFunction;
 
   /**
    * Remaining number of callbacks functions that must reach a 'done' state
@@ -57,16 +57,18 @@
   Duration _runningTime;
   Duration get runningTime => _runningTime;
 
-  bool enabled = true;
+  bool _enabled = true;
+
+  bool get enabled => _enabled;
 
   bool _doneTeardown = false;
 
   Completer _testComplete;
 
-  TestCase._internal(this.id, this.description, this.testFunction)
+  TestCase._internal(this.id, this.description, this._testFunction)
       : currentGroup = _currentContext.fullName,
-        setUp = _currentContext.testSetup,
-        tearDown = _currentContext.testTeardown;
+        _setUp = _currentContext.testSetup,
+        _tearDown = _currentContext.testTeardown;
 
   bool get isComplete => !enabled || result != null;
 
@@ -76,9 +78,9 @@
     }
     if (result == null || result == PASS) {
       if (e is TestFailure) {
-        fail("$e", stack);
+        _fail("$e", stack);
       } else {
-        error("$stage failed: Caught $e", stack);
+        _error("$stage failed: Caught $e", stack);
       }
     }
   };
@@ -97,7 +99,7 @@
 
     // Avoid calling [new Future] to avoid issue 11911.
     return new Future.value().then((_) {
-      if (setUp != null) return setUp();
+      if (_setUp != null) return _setUp();
     }).catchError(_errorHandler('Setup'))
         .then((_) {
           // Skip the test if setup failed.
@@ -106,7 +108,7 @@
           _startTime = new DateTime.now();
           _runningTime = null;
           ++_callbackFunctionsOutstanding;
-          return testFunction();
+          return _testFunction();
         })
         .catchError(_errorHandler('Test'))
         .then((_) {
@@ -115,12 +117,12 @@
             // Outstanding callbacks exist; we need to return a Future.
             _testComplete = new Completer();
             return _testComplete.future.whenComplete(() {
-              if (tearDown != null) {
-                return tearDown();
+              if (_tearDown != null) {
+                return _tearDown();
               }
             }).catchError(_errorHandler('Teardown'));
-          } else if (tearDown != null) {
-            return tearDown();
+          } else if (_tearDown != null) {
+            return _tearDown();
           }
         })
         .catchError(_errorHandler('Teardown'));
@@ -160,11 +162,11 @@
     }
   }
 
-  void pass() {
+  void _pass() {
     _complete(PASS);
   }
 
-  void fail(String messageText, [StackTrace stack]) {
+  void _fail(String messageText, [StackTrace stack]) {
     if (result != null) {
       String newMessage = (result == PASS)
           ? 'Test failed after initially passing: $messageText'
@@ -176,13 +178,13 @@
     }
   }
 
-  void error(String messageText, [StackTrace stack]) {
+  void _error(String messageText, [StackTrace stack]) {
     _complete(ERROR, messageText, stack);
   }
 
   void _markCallbackComplete() {
     if (--_callbackFunctionsOutstanding == 0 && !isComplete) {
-      pass();
+      _pass();
     }
   }
 
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index eae5a13..5fa2ae9 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -146,7 +146,9 @@
 import 'src/utils.dart';
 
 part 'src/configuration.dart';
+part 'src/group_context.dart';
 part 'src/simple_configuration.dart';
+part 'src/spread_args_helper.dart';
 part 'src/test_case.dart';
 
 Configuration _config;
@@ -207,79 +209,19 @@
 int _soloNestingLevel = 0;
 bool _soloTestSeen = false;
 
-/**
- * Setup and teardown functions for a group and its parents, the latter
- * for chaining.
- */
-class _GroupContext {
-  final _GroupContext parent;
-
-  /** Description text of the current test group. */
-  final String _name;
-
-  /** Setup function called before each test in a group. */
-  Function _testSetup;
-
-  get testSetup => _testSetup;
-
-  get parentSetup => (parent == null) ? null : parent.testSetup;
-
-  set testSetup(Function setup) {
-    var preSetup = parentSetup;
-    if (preSetup == null) {
-      _testSetup = setup;
-    } else {
-      _testSetup = () {
-        var f = preSetup();
-        if (f is Future) {
-          return f.then((_) => setup());
-        } else {
-          return setup();
-        }
-      };
-    }
-  }
-
-  /** Teardown function called after each test in a group. */
-  Function _testTeardown;
-
-  get testTeardown => _testTeardown;
-
-  get parentTeardown => (parent == null) ? null : parent.testTeardown;
-
-  set testTeardown(Function teardown) {
-    var postTeardown = parentTeardown;
-    if (postTeardown == null) {
-      _testTeardown = teardown;
-    } else {
-      _testTeardown = () {
-        var f = teardown();
-        if (f is Future) {
-          return f.then((_) => postTeardown());
-        } else {
-          return postTeardown();
-        }
-      };
-    }
-  }
-
-  String get fullName => (parent == null || parent == _rootContext)
-      ? _name
-      : "${parent.fullName}$groupSep$_name";
-
-  _GroupContext([this.parent, this._name = '']) {
-    _testSetup = parentSetup;
-    _testTeardown = parentTeardown;
-  }
-}
-
 // We use a 'dummy' context for the top level to eliminate null
 // checks when querying the context. This allows us to easily
 //  support top-level setUp/tearDown functions as well.
 final _rootContext = new _GroupContext();
 _GroupContext _currentContext = _rootContext;
 
-int _currentTestCaseIndex = 0;
+/**
+ * Represents the index of the currently running test case
+ * == -1 implies the test system is not running
+ * == [number of test cases] is a short-lived state flagging that the last test
+ *    has completed
+ */
+int _currentTestCaseIndex = -1;
 
 /** [TestCase] currently being executed. */
 TestCase get currentTestCase =>
@@ -293,7 +235,7 @@
 String _uncaughtErrorMessage = null;
 
 /** Time since we last gave non-sync code a chance to be scheduled. */
-var _lastBreath = new DateTime.now().millisecondsSinceEpoch;
+int _lastBreath = new DateTime.now().millisecondsSinceEpoch;
 
 /* Test case result strings. */
 // TODO(gram) we should change these constants to use a different string
@@ -313,6 +255,7 @@
  * calls.
  */
 void test(String spec, TestFunction body) {
+  _requireNotRunning();
   ensureInitialized();
   if (!_soloTestSeen || _soloNestingLevel > 0) {
     var testcase = new TestCase._internal(testCases.length + 1, _fullSpec(spec),
@@ -341,6 +284,7 @@
  * fact that they are effectively no-ops.
  */
 void solo_test(String spec, TestFunction body) {
+  _requireNotRunning();
   ensureInitialized();
   if (!_soloTestSeen) {
     _soloTestSeen = true;
@@ -355,133 +299,6 @@
   }
 }
 
-/** Sentinel value for [_SpreadArgsHelper]. */
-class _Sentinel {
-  const _Sentinel();
-}
-
-/** Simulates spread arguments using named arguments. */
-// TODO(sigmund): remove this class and simply use a closure with named
-// arguments (if still applicable).
-class _SpreadArgsHelper {
-  final Function callback;
-  final int minExpectedCalls;
-  final int maxExpectedCalls;
-  final Function isDone;
-  final String id;
-  int actualCalls = 0;
-  final TestCase testCase;
-  bool complete;
-  static const sentinel = const _Sentinel();
-
-  _SpreadArgsHelper(Function callback, int minExpected, int maxExpected,
-      Function isDone, String id)
-      : this.callback = callback,
-        minExpectedCalls = minExpected,
-        maxExpectedCalls = (maxExpected == 0 && minExpected > 0)
-            ? minExpected
-            : maxExpected,
-        this.isDone = isDone,
-        this.testCase = currentTestCase,
-        this.id = _makeCallbackId(id, callback) {
-    ensureInitialized();
-    if (testCase == null) {
-      throw new StateError("No valid test. Did you forget to run your test "
-          "inside a call to test()?");
-    }
-
-    if (isDone != null || minExpected > 0) {
-      testCase._callbackFunctionsOutstanding++;
-      complete = false;
-    } else {
-      complete = true;
-    }
-  }
-
-  static String _makeCallbackId(String id, Function callback) {
-    // Try to create a reasonable id.
-    if (id != null) {
-      return "$id ";
-    } else {
-      // If the callback is not an anonymous closure, try to get the
-      // name.
-      var fname = callback.toString();
-      var prefix = "Function '";
-      var pos = fname.indexOf(prefix);
-      if (pos > 0) {
-        pos += prefix.length;
-        var epos = fname.indexOf("'", pos);
-        if (epos > 0) {
-          return "${fname.substring(pos, epos)} ";
-        }
-      }
-    }
-    return '';
-  }
-
-  bool shouldCallBack() {
-    ++actualCalls;
-    if (testCase.isComplete) {
-      // Don't run if the test is done. We don't throw here as this is not
-      // the current test, but we do mark the old test as having an error
-      // if it previously passed.
-      if (testCase.result == PASS) {
-        testCase.error(
-            'Callback ${id}called ($actualCalls) after test case '
-            '${testCase.description} has already been marked as '
-            '${testCase.result}.');
-      }
-      return false;
-    } else if (maxExpectedCalls >= 0 && actualCalls > maxExpectedCalls) {
-      throw new TestFailure('Callback ${id}called more times than expected '
-                            '($maxExpectedCalls).');
-    }
-    return true;
-  }
-
-  void after() {
-    if (!complete) {
-      if (minExpectedCalls > 0 && actualCalls < minExpectedCalls) return;
-      if (isDone != null && !isDone()) return;
-
-      // Mark this callback as complete and remove it from the testcase
-      // oustanding callback count; if that hits zero the testcase is done.
-      complete = true;
-      testCase._markCallbackComplete();
-    }
-  }
-
-  invoke0() {
-    return _guardAsync(
-        () {
-          if (shouldCallBack()) {
-            return callback();
-          }
-        },
-        after, testCase);
-  }
-
-  invoke1(arg1) {
-    return _guardAsync(
-        () {
-          if (shouldCallBack()) {
-            return callback(arg1);
-          }
-        },
-        after, testCase);
-  }
-
-  invoke2(arg1, arg2) {
-    return _guardAsync(
-        () {
-          if (shouldCallBack()) {
-            return callback(arg1, arg2);
-          }
-        },
-        after, testCase);
-  }
-}
-
 /**
  * Indicate that [callback] is expected to be called a [count] number of times
  * (by default 1). The unittest framework will wait for the callback to run the
@@ -549,33 +366,39 @@
 }
 
 /**
- * Wraps the [callback] in a new function and returns that function. The new
- * function will be able to handle exceptions by directing them to the correct
- * test. This is thus similar to expectAsync0. Use it to wrap any callbacks that
- * might optionally be called but may never be called during the test.
- * [callback] should take 0 positional arguments (named arguments are not
- * supported). [id] can be used to identify the callback in error
- * messages (for example if it is called after the test case is complete).
+ * *Deprecated*
+ *
+ * All tests are now run an isolated [Zone].
+ *
+ * You can safely remove calls to this method.
  */
-// TODO(sigmund): deprecate this API when issue 2706 is fixed.
+@deprecated
 Function protectAsync0(Function callback, {String id}) {
-  return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke0;
+  return callback;
 }
 
 /**
- * Like [protectAsync0] but [callback] should take 1 positional argument.
+ * *Deprecated*
+ *
+ * All tests are now run an isolated [Zone].
+ *
+ * You can safely remove calls to this method.
  */
-// TODO(sigmund): deprecate this API when issue 2706 is fixed.
+@deprecated
 Function protectAsync1(Function callback, {String id}) {
-  return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke1;
+  return callback;
 }
 
 /**
- * Like [protectAsync0] but [callback] should take 2 positional arguments.
+ * *Deprecated*
+ *
+ * All tests are now run an isolated [Zone].
+ *
+ * You can safely remove calls to this method.
  */
-// TODO(sigmund): deprecate this API when issue 2706 is fixed.
+@deprecated
 Function protectAsync2(Function callback, {String id}) {
-  return new _SpreadArgsHelper(callback, 0, -1, null, id).invoke2;
+  return callback;
 }
 
 /**
@@ -584,6 +407,7 @@
  */
 void group(String description, void body()) {
   ensureInitialized();
+  _requireNotRunning();
   _currentContext = new _GroupContext(_currentContext, description);
   try {
     body();
@@ -601,6 +425,7 @@
 
 /** Like [solo_test], but for groups. */
 void solo_group(String description, void body()) {
+  _requireNotRunning();
   ensureInitialized();
   if (!_soloTestSeen) {
     _soloTestSeen = true;
@@ -623,6 +448,7 @@
  * case it must return a [Future].
  */
 void setUp(Function setupTest) {
+  _requireNotRunning();
   _currentContext.testSetup = setupTest;
 }
 
@@ -635,6 +461,7 @@
  * case it must return a [Future].
  */
 void tearDown(Function teardownTest) {
+  _requireNotRunning();
   _currentContext.testTeardown = teardownTest;
 }
 
@@ -651,18 +478,12 @@
   var msg = '$message\nCaught $e';
 
   if (currentTestCase != null) {
-    currentTestCase.error(msg, stack);
+    currentTestCase._error(msg, stack);
   } else {
     _uncaughtErrorMessage = "$msg: $stack";
   }
 }
 
-void rerunTests() {
-  _uncaughtErrorMessage = null;
-  _initialized = true; // We don't want to reset the test array.
-  runTests();
-}
-
 /**
  * Filter the tests. [testFilter] can be a [RegExp], a [String] or a
  * predicate function. This is different to enabling/disabling tests
@@ -683,6 +504,7 @@
 
 /** Runs all queued tests, one at a time. */
 void runTests() {
+  _requireNotRunning();
   _ensureInitialized(false);
   _currentTestCaseIndex = 0;
   _config.onStart();
@@ -690,24 +512,15 @@
 }
 
 /**
- * Run [tryBody] guarded in a try-catch block. If an exception is thrown, it is
- * passed to the corresponding test.
+ * *Deprecated*
  *
- * The value returned by [tryBody] (if any) is returned by [guardAsync].
+ * All tests are now run an isolated [Zone].
+ *
+ * You can safely remove calls to this method.
  */
+@deprecated
 guardAsync(Function tryBody) {
-  return _guardAsync(tryBody, null, currentTestCase);
-}
-
-_guardAsync(Function tryBody, Function finallyBody, TestCase testCase) {
-  assert(testCase != null);
-  try {
-    return tryBody();
-  } catch (e, trace) {
-    _registerException(testCase, e, trace);
-  } finally {
-    if (finallyBody != null) finallyBody();
-  }
+  return tryBody();
 }
 
 /**
@@ -723,9 +536,9 @@
 void _registerException(TestCase testCase, e, [trace]) {
   String message = (e is TestFailure) ? e.message : 'Caught $e';
   if (testCase.result == null) {
-    testCase.fail(message, trace);
+    testCase._fail(message, trace);
   } else {
-    testCase.error(message, trace);
+    testCase._error(message, trace);
   }
 }
 
@@ -734,16 +547,23 @@
  */
 void _runTest() {
   if (_currentTestCaseIndex >= testCases.length) {
+    assert(_currentTestCaseIndex == testCases.length);
     _completeTests();
   } else {
-    final testCase = testCases[_currentTestCaseIndex];
-    var f = _guardAsync(testCase._run, null, testCase);
+    var testCase = testCases[_currentTestCaseIndex];
+    Future f = runZoned(testCase._run, onError: (error, stack) {
+      // TODO(kevmoo) Do a better job of flagging these are async errors.
+      // https://code.google.com/p/dart/issues/detail?id=16530
+      _registerException(testCase, error, stack);
+    });
+
+    var timeout = unittestConfiguration.timeout;
+
     Timer timer;
-    final Duration timeout = unittestConfiguration.timeout;
     if (timeout != null) {
       try {
         timer = new Timer(timeout, () {
-          testCase.error("Test timed out after ${timeout.inSeconds} seconds.");
+          testCase._error("Test timed out after ${timeout.inSeconds} seconds.");
           _nextTestCase();
         });
       } on UnsupportedError catch (e) {
@@ -782,6 +602,7 @@
   _config.onDone(passed > 0 && failed == 0 && errors == 0 &&
       _uncaughtErrorMessage == null);
   _initialized = false;
+  _currentTestCaseIndex = -1;
 }
 
 String _fullSpec(String spec) {
@@ -824,11 +645,11 @@
 void _setTestEnabledState(int testId, bool state) {
   // Try fast path first.
   if (testCases.length > testId && testCases[testId].id == testId) {
-    testCases[testId].enabled = state;
+    testCases[testId]._enabled = state;
   } else {
     for (var i = 0; i < testCases.length; i++) {
       if (testCases[i].id == testId) {
-        testCases[i].enabled = state;
+        testCases[i]._enabled = state;
         break;
       }
     }
@@ -858,6 +679,12 @@
  */
 bool filterStacks = true;
 
+void _requireNotRunning() {
+  if(_currentTestCaseIndex != -1) {
+    throw new StateError('Not allowed when tests are running.');
+  }
+}
+
 /**
  * Returns a Trace object from a StackTrace object or a String, or the
  * unchanged input if formatStacks is false;
diff --git a/pkg/unittest/pubspec.yaml b/pkg/unittest/pubspec.yaml
index 66d6839..b0caec5 100644
--- a/pkg/unittest/pubspec.yaml
+++ b/pkg/unittest/pubspec.yaml
@@ -1,5 +1,5 @@
 name: unittest
-version: 0.9.3-dev+1
+version: 0.10.0-dev
 author: Dart Team <misc@dartlang.org>
 description: A library for writing dart unit tests.
 homepage: http://www.dartlang.org
diff --git a/pkg/unittest/test/unitttest_group_name_test.dart b/pkg/unittest/test/unittest_group_name_test.dart
similarity index 100%
rename from pkg/unittest/test/unitttest_group_name_test.dart
rename to pkg/unittest/test/unittest_group_name_test.dart
diff --git a/pkg/unittest/test/unittest_invalid_ops_test.dart b/pkg/unittest/test/unittest_invalid_ops_test.dart
new file mode 100644
index 0000000..4f1091c
--- /dev/null
+++ b/pkg/unittest/test/unittest_invalid_ops_test.dart
@@ -0,0 +1,26 @@
+// 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.
+
+library unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testName = 'invalid ops throw while test is running';
+
+var testFunction = (_) {
+  test(testName, () {
+    expect(() => test('test', () {}), throwsStateError);
+    expect(() => solo_test('test', () {}), throwsStateError);
+    expect(() => group('test', () {}), throwsStateError);
+    expect(() => solo_group('test', () {}), throwsStateError);
+    expect(() => setUp(() {}), throwsStateError);
+    expect(() => tearDown(() {}), throwsStateError);
+    expect(() => runTests(), throwsStateError);
+  });
+};
+
+var expected = buildStatusString(1, 0, 0, testName);
diff --git a/pkg/unittest/test/unittest_protect_async_test.dart b/pkg/unittest/test/unittest_protect_async_test.dart
new file mode 100644
index 0000000..12ded3c
--- /dev/null
+++ b/pkg/unittest/test/unittest_protect_async_test.dart
@@ -0,0 +1,43 @@
+// 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.
+
+library unittestTest;
+import 'dart:isolate';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+
+part 'unittest_test_utils.dart';
+
+var testFunction = (_) {
+  test('protectAsync0', () {
+    var protected = protectAsync0(() {
+      throw new StateError('error during protectAsync0');
+    });
+    new Future(protected);
+  });
+
+  test('protectAsync1', () {
+    var protected = protectAsync1((arg) {
+      throw new StateError('error during protectAsync1: $arg');
+    });
+    new Future(() => protected('one arg'));
+  });
+
+  test('protectAsync2', () {
+    var protected = protectAsync2((arg1, arg2) {
+      throw new StateError('error during protectAsync2: $arg1, $arg2');
+    });
+    new Future(() => protected('arg1', 'arg2'));
+  });
+
+  test('throw away 1', () {
+    return new Future(() {});
+  });
+};
+
+var expected = '1:0:3:4:0:::null:'
+  'protectAsync0:Caught Bad state: error during protectAsync0:'
+  'protectAsync1:Caught Bad state: error during protectAsync1: one arg:'
+  'protectAsync2:Caught Bad state: error during protectAsync2: arg1, arg2:'
+  'throw away 1:';
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 27b0eea..eefdd58 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -16,11 +16,13 @@
 
 #undef DeleteFile
 
+#define MAX_LONG_PATH 32767
+
 namespace dart {
 namespace bin {
 
 PathBuffer::PathBuffer() : length_(0) {
-  data_ = calloc(MAX_PATH + 1,  sizeof(wchar_t));  // NOLINT
+  data_ = calloc(MAX_LONG_PATH + 1,  sizeof(wchar_t));  // NOLINT
 }
 
 char* PathBuffer::AsString() const {
@@ -41,13 +43,13 @@
 bool PathBuffer::AddW(const wchar_t* name) {
   wchar_t* data = AsStringW();
   int written = _snwprintf(data + length_,
-                           MAX_PATH - length_,
+                           MAX_LONG_PATH - length_,
                            L"%s",
                            name);
-  data[MAX_PATH] = L'\0';
-  if (written <= MAX_PATH - length_ &&
+  data[MAX_LONG_PATH] = L'\0';
+  if (written <= MAX_LONG_PATH - length_ &&
       written >= 0 &&
-      static_cast<size_t>(written) == wcsnlen(name, MAX_PATH + 1)) {
+      static_cast<size_t>(written) == wcsnlen(name, MAX_LONG_PATH + 1)) {
     length_ += written;
     return true;
   } else {
@@ -390,7 +392,8 @@
 
 char* Directory::SystemTemp() {
   PathBuffer path;
-  path.Reset(GetTempPathW(MAX_PATH, path.AsStringW()) - 1);  // Remove \ at end.
+  // Remove \ at end.
+  path.Reset(GetTempPathW(MAX_LONG_PATH, path.AsStringW()) - 1);
   return path.AsString();
 }
 
@@ -407,7 +410,7 @@
   free(const_cast<wchar_t*>(system_prefix));
 
   // Length of xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 36.
-  if (path.length() > MAX_PATH - 36) {
+  if (path.length() > MAX_LONG_PATH - 36) {
     return NULL;
   }
 
diff --git a/runtime/bin/eventhandler.cc b/runtime/bin/eventhandler.cc
index 0c5b765..90eddd09 100644
--- a/runtime/bin/eventhandler.cc
+++ b/runtime/bin/eventhandler.cc
@@ -106,12 +106,7 @@
     UNREACHABLE();
   }
   int64_t data = DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 2));
-  if ((id == kTimerId) && (data == 0)) {
-    // This is a 0-timer. Simply queue a 'null' on the port.
-    DartUtils::PostNull(dart_port);
-  } else {
-    event_handler->SendData(id, dart_port, data);
-  }
+  event_handler->SendData(id, dart_port, data);
 }
 
 }  // namespace bin
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index b6ac1ce..993670c 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -988,7 +988,9 @@
 
       Handle::ScopedLock lock(handle);
 
-      if (!handle->IsError()) {
+      if (handle->IsError()) {
+        DartUtils::PostInt32(msg->dart_port, 1 << kErrorEvent);
+      } else {
         if ((msg->data & ((1 << kInEvent) | (1 << kOutEvent))) != 0) {
           // Only set mask if we turned on kInEvent or kOutEvent.
           handle->SetPortAndMask(msg->dart_port, msg->data);
diff --git a/runtime/bin/file_system_entity_patch.dart b/runtime/bin/file_system_entity_patch.dart
index e6b3fdc..24782aa 100644
--- a/runtime/bin/file_system_entity_patch.dart
+++ b/runtime/bin/file_system_entity_patch.dart
@@ -3,7 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 patch class FileStat {
-  /* patch */ static List<int> _statSync(String path) native "File_Stat";
+  /* patch */ static _statSync(String path) native "File_Stat";
 }
 
 
diff --git a/runtime/bin/file_system_watcher_macos.cc b/runtime/bin/file_system_watcher_macos.cc
index 678f45f..2fa80a2 100644
--- a/runtime/bin/file_system_watcher_macos.cc
+++ b/runtime/bin/file_system_watcher_macos.cc
@@ -55,37 +55,88 @@
  public:
   class Node {
    public:
-    Node(intptr_t base_path_length, int read_fd, int write_fd, bool recursive)
-      : base_path_length_(base_path_length),
-        read_fd_(read_fd),
-        write_fd_(write_fd),
-        recursive_(recursive),
-        ref_(NULL) {}
+    Node(FSEventsWatcher* watcher, intptr_t base_path_length, int read_fd,
+         int write_fd, bool recursive)
+        : watcher_(watcher),
+          ready_(false),
+          base_path_length_(base_path_length),
+          read_fd_(read_fd),
+          write_fd_(write_fd),
+          recursive_(recursive),
+          ref_(NULL) {}
 
     ~Node() {
       close(write_fd_);
-      FSEventStreamInvalidate(ref_);
-      FSEventStreamRelease(ref_);
     }
 
     void set_ref(FSEventStreamRef ref) {
       ref_ = ref;
     }
 
+    static void StartCallback(CFRunLoopTimerRef timer, void* info) {
+      Node* node = reinterpret_cast<Node*>(info);
+      FSEventStreamScheduleWithRunLoop(
+          node->ref_,
+          node->watcher_->run_loop_,
+          kCFRunLoopDefaultMode);
+      FSEventStreamStart(node->ref_);
+      FSEventStreamFlushSync(node->ref_);
+      node->watcher_->monitor_.Enter();
+      node->ready_ = true;
+      node->watcher_->monitor_.Notify();
+      node->watcher_->monitor_.Exit();
+    }
+
     void Start() {
-      FSEventStreamStart(ref_);
+      ASSERT(!ready_);
+      CFRunLoopTimerContext context;
+      memset(&context, 0, sizeof(context));
+      context.info = this;
+      CFRunLoopTimerRef timer = CFRunLoopTimerCreate(
+          NULL, 0, 0, 0, 0, StartCallback, &context);
+      CFRunLoopAddTimer(watcher_->run_loop_, timer, kCFRunLoopCommonModes);
+      watcher_->monitor_.Enter();
+      while (!ready_) {
+        watcher_->monitor_.Wait(Monitor::kNoTimeout);
+      }
+      watcher_->monitor_.Exit();
+    }
+
+    static void StopCallback(CFRunLoopTimerRef timer, void* info) {
+      Node* node = reinterpret_cast<Node*>(info);
+      FSEventStreamStop(node->ref_);
+      FSEventStreamInvalidate(node->ref_);
+      FSEventStreamRelease(node->ref_);
+      node->watcher_->monitor_.Enter();
+      node->ready_ = false;
+      node->watcher_->monitor_.Notify();
+      node->watcher_->monitor_.Exit();
     }
 
     void Stop() {
-      FSEventStreamStop(ref_);
+      ASSERT(ready_);
+      CFRunLoopTimerContext context;
+      memset(&context, 0, sizeof(context));
+      context.info = this;
+      CFRunLoopTimerRef timer = CFRunLoopTimerCreate(
+          NULL, 0, 0, 0, 0, StopCallback, &context);
+      CFRunLoopAddTimer(watcher_->run_loop_, timer, kCFRunLoopCommonModes);
+      watcher_->monitor_.Enter();
+      while (ready_) {
+        watcher_->monitor_.Wait(Monitor::kNoTimeout);
+      }
+      watcher_->monitor_.Exit();
     }
 
+    bool ready() const { return ready_; }
     intptr_t base_path_length() const { return base_path_length_; }
     int read_fd() const { return read_fd_; }
     int write_fd() const { return write_fd_; }
     bool recursive() const { return recursive_; }
 
    private:
+    FSEventsWatcher* watcher_;
+    bool ready_;
     intptr_t base_path_length_;
     int read_fd_;
     int write_fd_;
@@ -143,7 +194,7 @@
     CFStringRef path_ref = CFStringCreateWithCString(
         NULL, base_path, kCFStringEncodingUTF8);
 
-    Node* node = new Node(strlen(base_path), fds[0], fds[1], recursive);
+    Node* node = new Node(this, strlen(base_path), fds[0], fds[1], recursive);
 
     FSEventStreamContext context;
     context.version = 0;
@@ -162,11 +213,6 @@
 
     node->set_ref(ref);
 
-    FSEventStreamScheduleWithRunLoop(
-        ref,
-        run_loop_,
-        kCFRunLoopDefaultMode);
-
     return node;
   }
 
@@ -178,6 +224,9 @@
                        const FSEventStreamEventFlags event_flags[],
                        const FSEventStreamEventId event_ids[]) {
     Node* node = reinterpret_cast<Node*>(client);
+    // `ready` is set on same thread as this callback is invoked, so we don't
+    // need to lock here.
+    if (!node->ready()) return;
     for (size_t i = 0; i < num_events; i++) {
       char *path = reinterpret_cast<char**>(event_paths)[i];
       FSEvent event;
@@ -207,7 +256,7 @@
   FSEventsWatcher* watcher = new FSEventsWatcher();
   watcher->monitor().Enter();
   while (!watcher->has_run_loop()) {
-    watcher->monitor().Wait(1);
+    watcher->monitor().Wait(Monitor::kNoTimeout);
   }
   watcher->monitor().Exit();
   return reinterpret_cast<intptr_t>(watcher);
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index 5d17d04..eda6e9b 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -635,13 +635,14 @@
 
 static Mutex* signal_mutex = new Mutex();
 static SignalInfo* signal_handlers = NULL;
-static const int kSignalsCount = 5;
+static const int kSignalsCount = 6;
 static const int kSignals[kSignalsCount] = {
+  SIGHUP,
   SIGINT,
-  SIGWINCH,
   SIGTERM,
   SIGUSR1,
-  SIGUSR2
+  SIGUSR2,
+  SIGWINCH
 };
 
 
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index 175e36d..037dd16 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -634,13 +634,14 @@
 
 static Mutex* signal_mutex = new Mutex();
 static SignalInfo* signal_handlers = NULL;
-static const int kSignalsCount = 5;
+static const int kSignalsCount = 6;
 static const int kSignals[kSignalsCount] = {
+  SIGHUP,
   SIGINT,
-  SIGWINCH,
   SIGTERM,
   SIGUSR1,
-  SIGUSR2
+  SIGUSR2,
+  SIGWINCH
 };
 
 
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index e369b21..c2d8b20 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -676,13 +676,14 @@
 
 static Mutex* signal_mutex = new Mutex();
 static SignalInfo* signal_handlers = NULL;
-static const int kSignalsCount = 5;
+static const int kSignalsCount = 6;
 static const int kSignals[kSignalsCount] = {
+  SIGHUP,
   SIGINT,
-  SIGWINCH,
   SIGTERM,
   SIGUSR1,
-  SIGUSR2
+  SIGUSR2,
+  SIGWINCH
 };
 
 
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index cab5b49..78cae4f 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -130,6 +130,7 @@
   /* patch */ static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
     if (signal != ProcessSignal.SIGHUP &&
         signal != ProcessSignal.SIGINT &&
+        signal != ProcessSignal.SIGTERM &&
         (Platform.isWindows ||
          (signal != ProcessSignal.SIGUSR1 &&
           signal != ProcessSignal.SIGUSR2 &&
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index 75c7d47..2cc3de7 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -876,12 +876,20 @@
 DART_EXPORT Dart_Isolate Dart_CurrentIsolate();
 
 /**
- * Returns the callback data which was passed to the isolate when it
- * was created.
+ * Returns the callback data associated with the current Isolate. This data was
+ * passed to the isolate when it was created.
  */
 DART_EXPORT void* Dart_CurrentIsolateData();
 
 /**
+ * Returns the callback data associated with the specified Isolate. This data
+ * was passed to the isolate when it was created.
+ * The embedder is responsible for ensuring the consistency of this data
+ * with respect to the lifecycle of an Isolate.
+ */
+DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate);
+
+/**
  * Returns the debugging name for the current isolate.
  *
  * This name is unique to each isolate and should only be used to make
diff --git a/runtime/lib/convert_patch.dart b/runtime/lib/convert_patch.dart
index 3ba4f7e..93da461 100644
--- a/runtime/lib/convert_patch.dart
+++ b/runtime/lib/convert_patch.dart
@@ -2,6 +2,8 @@
 // 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.
 
+import "dart:typed_data";
+
 // JSON conversion.
 
 patch _parseJson(String json, reviver(var key, var value)) {
@@ -554,3 +556,9 @@
     throw new FormatException("Unexpected character at $position: $slice");
   }
 }
+
+// UTF-8 conversion.
+
+patch class _Utf8Encoder {
+  /* patch */ static List<int> _createBuffer(int size) => new Uint8List(size);
+}
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 80e830b..a5955a9 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -273,3 +273,9 @@
 
   static SendPort _spawnUri(String uri) native "Isolate_spawnUri";
 }
+
+patch class Capability {
+  /* patch */ factory Capability() {
+    throw new UnimplementedError();
+  }
+}
diff --git a/runtime/lib/math.cc b/runtime/lib/math.cc
index 801c8c6..8f773f9 100644
--- a/runtime/lib/math.cc
+++ b/runtime/lib/math.cc
@@ -111,38 +111,67 @@
 }
 
 
+uint64_t mix64(uint64_t n) {
+  // Thomas Wang 64-bit mix.
+  // http://www.concentric.net/~Ttwang/tech/inthash.htm
+  // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+  n = (~n) + (n << 21);           // n = (n << 21) - n - 1;
+  n = n ^ (n >> 24);
+  n = n * 265;                    // n = (n + (n << 3)) + (n << 8);
+  n = n ^ (n >> 14);
+  n = n * 21;                     // n = (n + (n << 2)) + (n << 4);
+  n = n ^ (n >> 28);
+  n = n + (n << 31);
+  return n;
+}
+
+
 // Implements:
+//   uint64_t hash = 0;
 //   do {
-//     seed = (seed + 0x5A17) & _Random._MASK_64;
-//   } while (seed == 0);
-//   _state[kSTATE_LO] = seed & _MASK_32;
-//   _state[kSTATE_HI] = seed >> 32;
+//      hash = hash * 1037 ^ mix64((uint64_t)seed);
+//      seed >>= 64;
+//   } while (seed != 0 && seed != -1);  // Limits if seed positive or negative.
+//   if (hash == 0) {
+//     hash = 0x5A17;
+//   }
+//   _state[kSTATE_LO] = hash & _MASK_32;
+//   _state[kSTATE_HI] = hash >> 32;
 DEFINE_NATIVE_ENTRY(Random_setupSeed, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(Instance, receiver, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, seed_int, arguments->NativeArgAt(1));
   const TypedData& array = TypedData::Handle(GetRandomStateArray(receiver));
   ASSERT(!seed_int.IsNull());
   ASSERT(!array.IsNull());
-  int64_t seed = 0;
+  uint64_t seed = 0;
   if (seed_int.IsBigint()) {
     const Bigint& mask64 = Bigint::Handle(
         BigintOperations::NewFromUint64(0xffffffffffffffffLL));
     Bigint& big_seed = Bigint::Handle();
     big_seed ^= seed_int.raw();
+    uint64_t negate_mask = 0;
+    if (big_seed.IsNegative()) {
+      // Negate bits to make seed positive.
+      // Negate bits again (by xor with negate_mask) when extracted below,
+      // to get original bits.
+      negate_mask = 0xffffffffffffffffLL;
+      big_seed ^= BigintOperations::BitNot(big_seed);
+    }
     Bigint& low64 = Bigint::Handle();
-    while (!big_seed.IsZero()) {
+    do {
       low64 = BigintOperations::BitAnd(big_seed, mask64);
       ASSERT(BigintOperations::FitsIntoUint64(low64));
-      seed ^= BigintOperations::ToUint64(low64);
+      uint64_t chunk = BigintOperations::ToUint64(low64) ^ negate_mask;
+      seed = (seed * 1037) ^ mix64(chunk);
       big_seed = BigintOperations::ShiftRight(big_seed, 64);
-    }
+    } while (!big_seed.IsZero());
   } else {
-    seed = seed_int.AsInt64Value();
+    seed = mix64(static_cast<uint64_t>(seed_int.AsInt64Value()));
   }
 
-  do {
-    seed = seed + 0x5A17;
-  } while (seed == 0);
+  if (seed == 0) {
+    seed = 0x5a17;
+  }
   array.SetUint32(0, static_cast<uint32_t>(seed));
   array.SetUint32(array.ElementSizeInBytes(),
       static_cast<uint32_t>(seed >> 32));
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 3b7391c..9f5c763 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -1301,6 +1301,33 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(Mirrors_evalInLibraryWithPrivateKey, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(String, expression, arguments->NativeArgAt(0));
+  GET_NATIVE_ARGUMENT(String, private_key, arguments->NativeArgAt(1));
+
+  const GrowableObjectArray& libraries =
+      GrowableObjectArray::Handle(isolate->object_store()->libraries());
+  const int num_libraries = libraries.Length();
+  Library& each_library = Library::Handle();
+  Library& ctxt_library = Library::Handle();
+  String& library_key = String::Handle();
+
+  if (library_key.IsNull()) {
+    ctxt_library = Library::CoreLibrary();
+  } else {
+    for (int i = 0; i < num_libraries; i++) {
+      each_library ^= libraries.At(i);
+      library_key = each_library.private_key();
+      if (library_key.Equals(private_key)) {
+        ctxt_library = each_library.raw();
+        break;
+      }
+    }
+  }
+  ASSERT(!ctxt_library.IsNull());
+  return ctxt_library.Evaluate(expression);
+}
+
 DEFINE_NATIVE_ENTRY(TypedefMirror_declaration, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(Type, type, arguments->NativeArgAt(0));
   const Class& cls = Class::Handle(type.type_class());
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index cd8182f..8f5a1a2 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -52,8 +52,9 @@
 }
 
 Map _makeMemberMap(List mirrors) {
-  return new _UnmodifiableMapView(
-      new Map<Symbol, dynamic>.fromIterable(mirrors, key: (e) => e.simpleName));
+  return new _UnmodifiableMapView<Symbol, DeclarationMirror>(
+      new Map<Symbol, DeclarationMirror>.fromIterable(
+          mirrors, key: (e) => e.simpleName));
 }
 
 String _n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
@@ -331,6 +332,95 @@
     return new _InvocationTrampoline(this, selector);
   }
 
+  // TODO(16539): Make these weak or soft.
+  static var _getFieldClosures = new HashMap();
+  static var _setFieldClosures = new HashMap();
+  static var _getFieldCallCounts = new HashMap();
+  static var _setFieldCallCounts = new HashMap();
+  static const _closureThreshold = 20;
+
+  _getFieldSlow(unwrapped) {
+    // Slow path factored out to give the fast path a better chance at being
+    // inlined.
+    var callCount = _getFieldCallCounts[unwrapped];
+    if (callCount == null) {
+      callCount = 0;
+    }
+    if (callCount == _closureThreshold) {
+      // We've seen a success getter invocation a few times: time to invest in a
+      // closure.
+      var f;
+      var atPosition = unwrapped.indexOf('@');
+      if (atPosition == -1) {
+        // Public symbol.
+        f = _eval('(x) => x.$unwrapped', null);
+      } else {
+        // Private symbol.
+        var withoutKey = unwrapped.substring(0, atPosition);
+        var privateKey = unwrapped.substring(atPosition);
+        f = _eval('(x) => x.$withoutKey', privateKey);
+      }
+      _getFieldClosures[unwrapped] = f;
+      _getFieldCallCounts.remove(unwrapped);  // We won't look for this again.
+      return reflect(f(_reflectee));
+    }
+    var result = reflect(_invokeGetter(_reflectee, unwrapped));
+    // Only update call count if we don't throw to avoid creating closures for
+    // non-existent getters.
+    _getFieldCallCounts[unwrapped] = callCount + 1;
+    return result;
+  }
+
+  InstanceMirror getField(Symbol memberName) {
+    var unwrapped = _n(memberName);
+    var f = _getFieldClosures[unwrapped];
+    return (f == null) ? _getFieldSlow(unwrapped) : reflect(f(_reflectee));
+  }
+
+  _setFieldSlow(unwrapped, arg) {
+    // Slow path factored out to give the fast path a better chance at being
+    // inlined.
+    var callCount = _setFieldCallCounts[unwrapped];
+    if (callCount == null) {
+      callCount = 0;
+    }
+    if (callCount == _closureThreshold) {
+      // We've seen a success getter invocation a few times: time to invest in a
+      // closure.
+      var f;
+      var atPosition = unwrapped.indexOf('@');
+      if (atPosition == -1) {
+        // Public symbol.
+        f = _eval('(x, v) => x.$unwrapped = v', null);
+      } else {
+        // Private symbol.
+        var withoutKey = unwrapped.substring(0, atPosition);
+        var privateKey = unwrapped.substring(atPosition);
+        f = _eval('(x, v) => x.$withoutKey = v', privateKey);
+      }
+      _setFieldClosures[unwrapped] = f;
+      _setFieldCallCounts.remove(unwrapped);
+      return reflect(f(_reflectee, arg));
+    }
+    _invokeSetter(_reflectee, unwrapped, arg);
+    var result = reflect(arg);
+    // Only update call count if we don't throw to avoid creating closures for
+    // non-existent setters.
+    _setFieldCallCounts[unwrapped] = callCount + 1;
+    return result;
+  }
+
+  InstanceMirror setField(Symbol memberName, arg) {
+    var unwrapped = _n(memberName);
+    var f = _setFieldClosures[unwrapped];
+    return (f == null)
+        ? _setFieldSlow(unwrapped, arg)
+        : reflect(f(_reflectee, arg));
+  }
+
+  static _eval(expression, privateKey)
+      native "Mirrors_evalInLibraryWithPrivateKey";
+
   // Override to include the receiver in the arguments.
   InstanceMirror invoke(Symbol memberName,
                         List positionalArguments,
@@ -653,7 +743,8 @@
       var constructorsList = _computeConstructors(_reflectee);
       var stringName = _n(simpleName);
       constructorsList.forEach((c) => c._patchConstructorName(stringName));
-      _cachedConstructors = _makeMemberMap(constructorsList);
+      _cachedConstructors =
+          new Map.fromIterable(constructorsList, key: (e) => e.simpleName);
     }
     return _cachedConstructors;
   }
diff --git a/runtime/lib/simd128.cc b/runtime/lib/simd128.cc
index d52530b..5485953 100644
--- a/runtime/lib/simd128.cc
+++ b/runtime/lib/simd128.cc
@@ -30,10 +30,10 @@
   GET_NON_NULL_NATIVE_ARGUMENT(Double, y, arguments->NativeArgAt(2));
   GET_NON_NULL_NATIVE_ARGUMENT(Double, z, arguments->NativeArgAt(3));
   GET_NON_NULL_NATIVE_ARGUMENT(Double, w, arguments->NativeArgAt(4));
-  float _x = x.value();
-  float _y = y.value();
-  float _z = z.value();
-  float _w = w.value();
+  float _x = static_cast<float>(x.value());
+  float _y = static_cast<float>(y.value());
+  float _z = static_cast<float>(z.value());
+  float _w = static_cast<float>(w.value());
   return Float32x4::New(_x, _y, _z, _w);
 }
 
@@ -60,6 +60,14 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(Float32x4_fromFloat64x2, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, v, arguments->NativeArgAt(1));
+  float _x = static_cast<float>(v.x());
+  float _y = static_cast<float>(v.y());
+  return Float32x4::New(_x, _y, 0.0f, 0.0f);
+}
+
+
 DEFINE_NATIVE_ENTRY(Float32x4_add, 2) {
   GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, self, arguments->NativeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, other, arguments->NativeArgAt(1));
@@ -708,4 +716,180 @@
 }
 
 
+DEFINE_NATIVE_ENTRY(Float64x2_fromDoubles, 3) {
+  ASSERT(AbstractTypeArguments::CheckedHandle(
+      arguments->NativeArgAt(0)).IsNull());
+  GET_NON_NULL_NATIVE_ARGUMENT(Double, x, arguments->NativeArgAt(1));
+  GET_NON_NULL_NATIVE_ARGUMENT(Double, y, arguments->NativeArgAt(2));
+  return Float64x2::New(x.value(), y.value());
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_splat, 2) {
+  ASSERT(AbstractTypeArguments::CheckedHandle(
+      arguments->NativeArgAt(0)).IsNull());
+  GET_NON_NULL_NATIVE_ARGUMENT(Double, v, arguments->NativeArgAt(1));
+  return Float64x2::New(v.value(), v.value());
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_zero, 1) {
+  ASSERT(AbstractTypeArguments::CheckedHandle(
+      arguments->NativeArgAt(0)).IsNull());
+  return Float64x2::New(0.0, 0.0);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_fromFloat32x4, 2) {
+  ASSERT(AbstractTypeArguments::CheckedHandle(
+      arguments->NativeArgAt(0)).IsNull());
+  GET_NON_NULL_NATIVE_ARGUMENT(Float32x4, v, arguments->NativeArgAt(1));
+  double _x = v.x();
+  double _y = v.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_add, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other, arguments->NativeArgAt(1));
+  double _x = self.x() + other.x();
+  double _y = self.y() + other.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_negate, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  double _x = -self.x();
+  double _y = -self.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_sub, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other, arguments->NativeArgAt(1));
+  double _x = self.x() - other.x();
+  double _y = self.y() - other.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_mul, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other, arguments->NativeArgAt(1));
+  double _x = self.x() * other.x();
+  double _y = self.y() * other.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_div, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other, arguments->NativeArgAt(1));
+  double _x = self.x() / other.x();
+  double _y = self.y() / other.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_scale, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Double, scale, arguments->NativeArgAt(1));
+  double _s = scale.value();
+  double _x = self.x() * _s;
+  double _y = self.y() * _s;
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_abs, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  double _x = fabs(self.x());
+  double _y = fabs(self.y());
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_clamp, 3) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, lo, arguments->NativeArgAt(1));
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, hi, arguments->NativeArgAt(2));
+  // The order of the clamping must match the order of the optimized code:
+  // MAX(MIN(self, hi), lo).
+  double _x = self.x() < hi.x() ? self.x() : hi.x();
+  double _y = self.y() < hi.y() ? self.y() : hi.y();
+  _x = _x < lo.x() ? lo.x() : _x;
+  _y = _y < lo.y() ? lo.y() : _y;
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_getX, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  return Double::New(self.x());
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_getY, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  return Double::New(self.y());
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_getSignMask, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  uint32_t mx = (bit_cast<uint64_t>(self.x()) & 0x8000000000000000LL) >> 63;
+  uint32_t my = (bit_cast<uint64_t>(self.y()) & 0x8000000000000000LL) >> 63;
+  uint32_t value = mx | (my << 1);
+  return Integer::New(value);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_setX, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Double, x, arguments->NativeArgAt(1));
+  double _x = x.value();
+  double _y = self.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_setY, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Double, y, arguments->NativeArgAt(1));
+  double _x = self.x();
+  double _y = y.value();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_min, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other,
+                               arguments->NativeArgAt(1));
+  double _x = self.x() < other.x() ? self.x() : other.x();
+  double _y = self.y() < other.y() ? self.y() : other.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_max, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, other,
+                               arguments->NativeArgAt(1));
+  double _x = self.x() > other.x() ? self.x() : other.x();
+  double _y = self.y() > other.y() ? self.y() : other.y();
+  return Float64x2::New(_x, _y);
+}
+
+
+DEFINE_NATIVE_ENTRY(Float64x2_sqrt, 1) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Float64x2, self, arguments->NativeArgAt(0));
+  double _x = sqrt(self.x());
+  double _y = sqrt(self.y());
+  return Float64x2::New(_x, _y);
+}
+
 }  // namespace dart
diff --git a/runtime/lib/typed_data.cc b/runtime/lib/typed_data.cc
index 406786e..0a10465 100644
--- a/runtime/lib/typed_data.cc
+++ b/runtime/lib/typed_data.cc
@@ -300,6 +300,8 @@
 TYPED_DATA_NATIVES(
     GetFloat32x4, SetFloat32x4, Float32x4, value, 16, simd128_value_t)
 TYPED_DATA_NATIVES(GetInt32x4, SetInt32x4, Int32x4, value, 16, simd128_value_t)
+TYPED_DATA_NATIVES(
+    GetFloat64x2, SetFloat64x2, Float64x2, value, 16, simd128_value_t)
 
 
 DEFINE_NATIVE_ENTRY(ByteData_ToEndianInt16, 2) {
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index aac1cda..7430819 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -230,6 +230,23 @@
 }
 
 
+patch class Float64x2List {
+  /* patch */ factory Float64x2List(int length) {
+    return new _Float64x2Array(length);
+  }
+
+  /* patch */ factory Float64x2List.fromList(List<Float64x2> elements) {
+    return new _Float64x2Array(elements.length)
+        ..setRange(0, elements.length, elements);
+  }
+
+  /* patch */ factory Float64x2List.view(ByteBuffer buffer,
+                                         [int offsetInBytes = 0, int length]) {
+    return new _Float64x2ArrayView(buffer, offsetInBytes, length);
+  }
+}
+
+
 patch class Float32x4 {
   /* patch */ factory Float32x4(double x, double y, double z, double w) {
     return new _Float32x4(x, y, z, w);
@@ -243,6 +260,9 @@
   /* patch */ factory Float32x4.fromInt32x4Bits(Int32x4 x) {
     return new _Float32x4.fromInt32x4Bits(x);
   }
+  /* patch */ factory Float32x4.fromFloat64x2(Float64x2 v) {
+    return new _Float32x4.fromFloat64x2(v);
+  }
 }
 
 
@@ -259,6 +279,25 @@
 }
 
 
+patch class Float64x2 {
+  /* patch */ factory Float64x2(double x, double y) {
+    return new _Float64x2(x, y);
+  }
+
+  /* patch */ factory Float64x2.splat(double v) {
+    return new _Float64x2.splat(v);
+  }
+
+  /* patch */ factory Float64x2.zero() {
+    return new _Float64x2.zero();
+  }
+
+  /* patch */ factory Float64x2.fromFloat32x4(Float32x4 v) {
+    return new _Float64x2.fromFloat32x4(v);
+  }
+}
+
+
 patch class ByteData {
   /* patch */ factory ByteData(int length) {
     var list = new _Uint8Array(length);
@@ -630,6 +669,10 @@
   Int32x4 _getInt32x4(int offsetInBytes) native "TypedData_GetInt32x4";
   void _setInt32x4(int offsetInBytes, Int32x4 value)
       native "TypedData_SetInt32x4";
+
+  Float64x2 _getFloat64x2(int offsetInBytes) native "TypedData_GetFloat64x2";
+  void _setFloat64x2(int offsetInBytes, Float64x2 value)
+      native "TypedData_SetFloat64x2";
 }
 
 
@@ -1420,6 +1463,67 @@
 }
 
 
+class _Float64x2Array extends _TypedList implements Float64x2List {
+  // Factory constructors.
+
+  factory _Float64x2Array(int length) {
+    return _new(length);
+  }
+
+  factory _Float64x2Array.view(ByteBuffer buffer,
+                               [int offsetInBytes = 0, int length]) {
+    if (length == null) {
+      length = (buffer.lengthInBytes - offsetInBytes) ~/
+               Float64x2List.BYTES_PER_ELEMENT;
+    }
+    return new _Float64x2ArrayView(buffer, offsetInBytes, length);
+  }
+
+
+  Float64x2 operator[](int index) {
+    if (index < 0 || index >= length) {
+      _throwRangeError(index, length);
+    }
+    return _getIndexedFloat64x2(index);
+  }
+
+  void operator[]=(int index, Float64x2 value) {
+    if (index < 0 || index >= length) {
+      _throwRangeError(index, length);
+    }
+    _setIndexedFloat64x2(index, value);
+  }
+
+  Iterator<Float64x2> get iterator {
+    return new _TypedListIterator<Float64x2>(this);
+  }
+
+
+  // Method(s) implementing the TypedData interface.
+
+  int get elementSizeInBytes {
+    return Float64x2List.BYTES_PER_ELEMENT;
+  }
+
+
+  // Internal utility methods.
+
+  _Float64x2Array _createList(int length) {
+    return _new(length);
+  }
+
+  Float64x2 _getIndexedFloat64x2(int index) {
+    return _getFloat64x2(index * Float64x2List.BYTES_PER_ELEMENT);
+  }
+
+  void _setIndexedFloat64x2(int index, Float64x2 value) {
+    _setFloat64x2(index * Float64x2List.BYTES_PER_ELEMENT, value);
+  }
+
+  static _Float64x2Array _new(int length) native "TypedData_Float64x2Array_new";
+}
+
+
 class _ExternalInt8Array extends _TypedList implements Int8List {
   // Factory constructors.
 
@@ -2111,6 +2215,61 @@
 }
 
 
+class _ExternalFloat64x2Array extends _TypedList implements Float64x2List {
+  // Factory constructors.
+
+  factory _ExternalFloat64x2Array(int length) {
+    return _new(length);
+  }
+
+
+  // Method(s) implementing the List interface.
+
+  Float64x2 operator[](int index) {
+    if (index < 0 || index >= length) {
+      _throwRangeError(index, length);
+    }
+    return _getIndexedFloat64x2(index);
+  }
+
+  void operator[]=(int index, Float64x2 value) {
+    if (index < 0 || index >= length) {
+      _throwRangeError(index, length);
+    }
+    _setIndexedFloat64x2(index, value);
+  }
+
+  Iterator<Float64x2> get iterator {
+    return new _TypedListIterator<Float64x2>(this);
+  }
+
+
+  // Method(s) implementing the TypedData interface.
+
+  int get elementSizeInBytes {
+    return Float64x2List.BYTES_PER_ELEMENT;
+  }
+
+
+  // Internal utility methods.
+
+  Float64x2List _createList(int length) {
+    return new Float64x2List(length);
+  }
+
+  Float64x2 _getIndexedFloat64x2(int index) {
+    return _getFloat64x2(index * Float64x2List.BYTES_PER_ELEMENT);
+  }
+
+  void _setIndexedFloat64x2(int index, Float64x2 value) {
+    _setFloat64x2(index * Float64x2List.BYTES_PER_ELEMENT, value);
+  }
+
+  static _ExternalFloat64x2Array _new(int length) native
+      "ExternalTypedData_Float64x2Array_new";
+}
+
+
 class _Float32x4 implements Float32x4 {
   factory _Float32x4(double x, double y, double z, double w)
       native "Float32x4_fromDoubles";
@@ -2118,6 +2277,8 @@
   factory _Float32x4.zero() native "Float32x4_zero";
   factory _Float32x4.fromInt32x4Bits(Int32x4 x)
       native "Float32x4_fromInt32x4Bits";
+  factory _Float32x4.fromFloat64x2(Float64x2 v)
+      native "Float32x4_fromFloat64x2";
   Float32x4 operator +(Float32x4 other) {
     return _add(other);
   }
@@ -2270,6 +2431,69 @@
       native "Int32x4_select";
 }
 
+
+class _Float64x2 implements Float64x2 {
+  factory _Float64x2(double x, double y) native "Float64x2_fromDoubles";
+  factory _Float64x2.splat(double v) native "Float64x2_splat";
+  factory _Float64x2.zero() native "Float64x2_zero";
+  factory _Float64x2.fromFloat32x4(Float32x4 v) native "Float64x2_fromFloat32x4";
+
+  Float64x2 operator +(Float64x2 other) {
+    return _add(other);
+  }
+  Float64x2 _add(Float64x2 other) native "Float64x2_add";
+  Float64x2 operator -() {
+    return _negate();
+  }
+  Float64x2 _negate() native "Float64x2_negate";
+  Float64x2 operator -(Float64x2 other) {
+    return _sub(other);
+  }
+  Float64x2 _sub(Float64x2 other) native "Float64x2_sub";
+  Float64x2 operator *(Float64x2 other) {
+    return _mul(other);
+  }
+  Float64x2 _mul(Float64x2 other) native "Float64x2_mul";
+  Float64x2 operator /(Float64x2 other) {
+    return _div(other);
+  }
+  Float64x2 _div(Float64x2 other) native "Float64x2_div";
+
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  Float64x2 scale(double s) native "Float64x2_scale";
+  /// Returns the absolute value of this [Float64x2].
+  Float64x2 abs() native "Float64x2_abs";
+
+  /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+  Float64x2 clamp(Float64x2 lowerLimit,
+                  Float64x2 upperLimit) native "Float64x2_clamp";
+
+  /// Extracted x value.
+  double get x native "Float64x2_getX";
+  /// Extracted y value.
+  double get y native "Float64x2_getY";
+
+  /// Extract the sign bits from each lane return them in the first 2 bits.
+  int get signMask native "Float64x2_getSignMask";
+
+  /// Returns a new [Float64x2] copied from [this] with a new x value.
+  Float64x2 withX(double x) native "Float64x2_setX";
+  /// Returns a new [Float64x2] copied from [this] with a new y value.
+  Float64x2 withY(double y) native "Float64x2_setY";
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float64x2 min(Float64x2 other) native "Float64x2_min";
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float64x2 max(Float64x2 other) native "Float64x2_max";
+
+  /// Returns the lane-wise square root of [this].
+  Float64x2 sqrt() native "Float64x2_sqrt";
+}
+
+
+
 class _TypedListIterator<E> implements Iterator<E> {
   final List<E> _array;
   final int _length;
@@ -2996,6 +3220,58 @@
 }
 
 
+class _Float64x2ArrayView extends _TypedListView implements Float64x2List {
+  // Constructor.
+  _Float64x2ArrayView(ByteBuffer buffer, [int _offsetInBytes = 0, int _length])
+    : super(buffer, _offsetInBytes,
+            _defaultIfNull(_length,
+                           ((buffer.lengthInBytes - _offsetInBytes) ~/
+                            Float64x2List.BYTES_PER_ELEMENT))) {
+    _rangeCheck(buffer.lengthInBytes,
+                offsetInBytes,
+                length * Float64x2List.BYTES_PER_ELEMENT);
+    _offsetAlignmentCheck(_offsetInBytes, Float64x2List.BYTES_PER_ELEMENT);
+  }
+
+
+  // Method(s) implementing List interface.
+
+  Float64x2 operator[](int index) {
+    if (index < 0 || index >= length) {
+      _throwRangeError(index, length);
+    }
+    return _typedData._getFloat64x2(offsetInBytes +
+                                    (index * Float64x2List.BYTES_PER_ELEMENT));
+  }
+
+  void operator[]=(int index, Float64x2 value) {
+    if (index < 0 || index >= length) {
+      _throwRangeError(index, length);
+    }
+    _typedData._setFloat64x2(offsetInBytes +
+                             (index * Float64x2List.BYTES_PER_ELEMENT), value);
+  }
+
+  Iterator<Float64x2> get iterator {
+    return new _TypedListIterator<Float64x2>(this);
+  }
+
+
+  // Method(s) implementing TypedData interface.
+
+  int get elementSizeInBytes {
+    return Float64x2List.BYTES_PER_ELEMENT;
+  }
+
+
+  // Internal utility methods.
+
+  Float64x2List _createList(int length) {
+    return new Float64x2List(length);
+  }
+}
+
+
 class _ByteDataView implements ByteData {
   _ByteDataView(ByteBuffer _buffer, int _offsetInBytes, int _lengthInBytes)
     : _typedData = _buffer,  // _buffer is guaranteed to be a TypedData here.
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 52adc16..b35c4f5 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -76,6 +76,7 @@
   union {
     float float_storage[4];
     int32_t int_storage[4];
+    double double_storage[2];
   };
   simd128_value_t& readFrom(const float* v) {
     float_storage[0] = v[0];
@@ -91,6 +92,11 @@
     int_storage[3] = v[3];
     return *this;
   }
+  simd128_value_t& readFrom(const double* v) {
+    double_storage[0] = v[0];
+    double_storage[1] = v[1];
+    return *this;
+  }
   simd128_value_t& readFrom(const simd128_value_t* v) {
     *this = *v;
     return *this;
@@ -107,6 +113,10 @@
     v[2] = int_storage[2];
     v[3] = int_storage[3];
   }
+  void writeTo(double* v) {
+    v[0] = double_storage[0];
+    v[1] = double_storage[1];
+  }
   void writeTo(simd128_value_t* v) {
     *v = *this;
   }
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index fd4ce60..cee8b72 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -256,9 +256,7 @@
   // library tag handler so that we can load all the bootstrap libraries.
   isolate->set_library_tag_handler(BootstrapLibraryTagHandler);
 
-  // Enter the Dart Scope as we will be calling back into the library
-  // tag handler when compiling the bootstrap libraries.
-  Dart_EnterScope();
+  HANDLESCOPE(isolate);
 
   // Create library objects for all the bootstrap libraries.
   for (intptr_t i = 0;
@@ -309,9 +307,6 @@
     SetupNativeResolver();
   }
 
-  // Exit the Dart scope.
-  Dart_ExitScope();
-
   // Restore the library tag handler for the isolate.
   isolate->set_library_tag_handler(saved_tag_handler);
 
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index efc972a..0c8faca 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -147,6 +147,7 @@
   V(TypedData_Float64Array_new, 1)                                             \
   V(TypedData_Float32x4Array_new, 1)                                           \
   V(TypedData_Int32x4Array_new, 1)                                             \
+  V(TypedData_Float64x2Array_new, 1)                                           \
   V(ExternalTypedData_Int8Array_new, 1)                                        \
   V(ExternalTypedData_Uint8Array_new, 1)                                       \
   V(ExternalTypedData_Uint8ClampedArray_new, 1)                                \
@@ -160,6 +161,7 @@
   V(ExternalTypedData_Float64Array_new, 1)                                     \
   V(ExternalTypedData_Float32x4Array_new, 1)                                   \
   V(ExternalTypedData_Int32x4Array_new, 1)                                     \
+  V(ExternalTypedData_Float64x2Array_new, 1)                                   \
   V(TypedData_length, 1)                                                       \
   V(TypedData_setRange, 5)                                                     \
   V(TypedData_GetInt8, 2)                                                      \
@@ -186,6 +188,8 @@
   V(TypedData_SetFloat32x4, 3)                                                 \
   V(TypedData_GetInt32x4, 2)                                                   \
   V(TypedData_SetInt32x4, 3)                                                   \
+  V(TypedData_GetFloat64x2, 2)                                                 \
+  V(TypedData_SetFloat64x2, 3)                                                 \
   V(ByteData_ToEndianInt16, 2)                                                 \
   V(ByteData_ToEndianUint16, 2)                                                \
   V(ByteData_ToEndianInt32, 2)                                                 \
@@ -197,6 +201,7 @@
   V(Float32x4_fromDoubles, 5)                                                  \
   V(Float32x4_splat, 2)                                                        \
   V(Float32x4_fromInt32x4Bits, 2)                                              \
+  V(Float32x4_fromFloat64x2, 2)                                                \
   V(Float32x4_zero, 1)                                                         \
   V(Float32x4_add, 2)                                                          \
   V(Float32x4_negate, 1)                                                       \
@@ -228,6 +233,26 @@
   V(Float32x4_sqrt, 1)                                                         \
   V(Float32x4_reciprocal, 1)                                                   \
   V(Float32x4_reciprocalSqrt, 1)                                               \
+  V(Float64x2_fromDoubles, 3)                                                  \
+  V(Float64x2_splat, 2)                                                        \
+  V(Float64x2_zero, 1)                                                         \
+  V(Float64x2_fromFloat32x4, 2)                                                \
+  V(Float64x2_add, 2)                                                          \
+  V(Float64x2_negate, 1)                                                       \
+  V(Float64x2_sub, 2)                                                          \
+  V(Float64x2_mul, 2)                                                          \
+  V(Float64x2_div, 2)                                                          \
+  V(Float64x2_scale, 2)                                                        \
+  V(Float64x2_abs, 1)                                                          \
+  V(Float64x2_clamp, 3)                                                        \
+  V(Float64x2_getX, 1)                                                         \
+  V(Float64x2_getY, 1)                                                         \
+  V(Float64x2_getSignMask, 1)                                                  \
+  V(Float64x2_setX, 2)                                                         \
+  V(Float64x2_setY, 2)                                                         \
+  V(Float64x2_min, 2)                                                          \
+  V(Float64x2_max, 2)                                                          \
+  V(Float64x2_sqrt, 1)                                                         \
   V(Int32x4_fromInts, 5)                                                       \
   V(Int32x4_fromBools, 5)                                                      \
   V(Int32x4_fromFloat32x4Bits, 2)                                              \
@@ -259,6 +284,7 @@
   V(Isolate_mainPort, 0)                                                       \
   V(Isolate_spawnFunction, 1)                                                  \
   V(Isolate_spawnUri, 1)                                                       \
+  V(Mirrors_evalInLibraryWithPrivateKey, 2)                                    \
   V(Mirrors_makeLocalClassMirror, 1)                                           \
   V(Mirrors_makeLocalTypeMirror, 1)                                            \
   V(Mirrors_makeLocalMirrorSystem, 0)                                          \
diff --git a/runtime/vm/cha.cc b/runtime/vm/cha.cc
index 5a4f54f..5c5ccb0 100644
--- a/runtime/vm/cha.cc
+++ b/runtime/vm/cha.cc
@@ -13,16 +13,27 @@
 namespace dart {
 
 bool CHA::HasSubclasses(intptr_t cid) {
+  Isolate* isolate = Isolate::Current();
+  const bool has_subclasses = HasSubclassesSafe(cid);
+  if (!has_subclasses) {
+    isolate->set_cha_used(true);
+  }
+  return has_subclasses;
+}
+
+
+bool CHA::HasSubclassesSafe(intptr_t cid) {
   ASSERT(cid >= kInstanceCid);
-  const ClassTable& class_table = *Isolate::Current()->class_table();
-  const Class& cls = Class::Handle(class_table.At(cid));
+  Isolate* isolate = Isolate::Current();
+  const ClassTable& class_table = *isolate->class_table();
+  const Class& cls = Class::Handle(isolate, class_table.At(cid));
   ASSERT(!cls.IsNull());
   if (cls.IsObjectClass()) {
     // Class Object has subclasses, although we do not keep track of them.
     return true;
   }
   const GrowableObjectArray& cls_direct_subclasses =
-      GrowableObjectArray::Handle(cls.direct_subclasses());
+      GrowableObjectArray::Handle(isolate, cls.direct_subclasses());
   return
       !cls_direct_subclasses.IsNull() && (cls_direct_subclasses.Length() > 0);
 }
@@ -61,26 +72,32 @@
 
 ZoneGrowableArray<intptr_t>* CHA::GetSubclassIdsOf(intptr_t cid) {
   ASSERT(cid > kInstanceCid);
-  const ClassTable& class_table = *Isolate::Current()->class_table();
-  const Class& cls = Class::Handle(class_table.At(cid));
+  Isolate* isolate = Isolate::Current();
+  const ClassTable& class_table = *isolate->class_table();
+  const Class& cls = Class::Handle(isolate, class_table.At(cid));
   ASSERT(!cls.IsNull());
   ZoneGrowableArray<intptr_t>* ids = new ZoneGrowableArray<intptr_t>();
   CollectSubclassIds(ids, cls);
+  isolate->set_cha_used(true);
   return ids;
 }
 
 
 bool CHA::HasOverride(const Class& cls, const String& function_name) {
+  Isolate* isolate = Isolate::Current();
   const GrowableObjectArray& cls_direct_subclasses =
-      GrowableObjectArray::Handle(cls.direct_subclasses());
+      GrowableObjectArray::Handle(isolate, cls.direct_subclasses());
   // Subclasses of Object are not tracked by CHA. Safely assume that overrides
   // exist.
-  if (cls.IsObjectClass()) return true;
+  if (cls.IsObjectClass()) {
+    return true;
+  }
 
   if (cls_direct_subclasses.IsNull()) {
+    isolate->set_cha_used(true);
     return false;
   }
-  Class& direct_subclass = Class::Handle();
+  Class& direct_subclass = Class::Handle(isolate);
   for (intptr_t i = 0; i < cls_direct_subclasses.Length(); i++) {
     direct_subclass ^= cls_direct_subclasses.At(i);
     // Unfinalized classes are treated as non-existent for CHA purposes,
@@ -94,6 +111,7 @@
       return true;
     }
   }
+  isolate->set_cha_used(true);
   return false;
 }
 
@@ -101,20 +119,22 @@
 ZoneGrowableArray<Function*>* CHA::GetNamedInstanceFunctionsOf(
     const ZoneGrowableArray<intptr_t>& cids,
     const String& function_name) {
+  Isolate* isolate = Isolate::Current();
   ASSERT(!function_name.IsNull());
-  const ClassTable& class_table = *Isolate::Current()->class_table();
+  const ClassTable& class_table = *isolate->class_table();
   ZoneGrowableArray<Function*>* functions = new ZoneGrowableArray<Function*>();
-  Class& cls = Class::Handle();
-  Function& cls_function = Function::Handle();
+  Class& cls = Class::Handle(isolate);
+  Function& cls_function = Function::Handle(isolate);
   for (intptr_t i = 0; i < cids.length(); i++) {
     const intptr_t cid = cids[i];
     ASSERT(cid > kInstanceCid);
     cls = class_table.At(cid);
     cls_function = cls.LookupDynamicFunction(function_name);
     if (!cls_function.IsNull()) {
-      functions->Add(&Function::ZoneHandle(cls_function.raw()));
+      functions->Add(&Function::ZoneHandle(isolate, cls_function.raw()));
     }
   }
+  isolate->set_cha_used(true);
   return functions;
 }
 
@@ -122,10 +142,12 @@
 ZoneGrowableArray<Function*>* CHA::GetOverridesOf(const Function& function) {
   ASSERT(!function.IsNull());
   ASSERT(function.IsDynamicFunction());
-  const Class& function_owner = Class::Handle(function.Owner());
-  const String& function_name = String::Handle(function.name());
+  Isolate* isolate = Isolate::Current();
+  const Class& function_owner = Class::Handle(isolate, function.Owner());
+  const String& function_name = String::Handle(isolate, function.name());
   ZoneGrowableArray<intptr_t>* cids = new ZoneGrowableArray<intptr_t>();
   CollectSubclassIds(cids, function_owner);
+  isolate->set_cha_used(true);
   return GetNamedInstanceFunctionsOf(*cids, function_name);
 }
 
diff --git a/runtime/vm/cha.h b/runtime/vm/cha.h
index d20445f..18a0bcb 100644
--- a/runtime/vm/cha.h
+++ b/runtime/vm/cha.h
@@ -19,6 +19,10 @@
   // Returns true if the class given by its cid has subclasses.
   static bool HasSubclasses(intptr_t cid);
 
+  // Use only on known private classes that can never be subclassed by lazy
+  // class finalization. Does not affect Isolate::use_cha flag.
+  static bool HasSubclassesSafe(intptr_t cid);
+
   // Returns an array containing the cids of the direct and indirect subclasses
   // of the class given by its cid.
   // Must not be called for kInstanceCid.
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 8c8abfc..7221924 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -36,30 +36,18 @@
 // optimizations may have become invalid.
 // Only methods which owner classes where subclasses can be invalid.
 // TODO(srdjan): Be even more precise by recording the exact CHA optimization.
-static void RemoveOptimizedCode(
+static void RemoveCHAOptimizedCode(
     const GrowableArray<intptr_t>& added_subclass_to_cids) {
   ASSERT(FLAG_use_cha);
   if (added_subclass_to_cids.is_empty()) return;
-  // Deoptimize all live frames.
-  DeoptimizeIfOwner(added_subclass_to_cids);
   // Switch all functions' code to unoptimized.
   const ClassTable& class_table = *Isolate::Current()->class_table();
   Class& cls = Class::Handle();
-  Array& array = Array::Handle();
-  Function& function = Function::Handle();
   for (intptr_t i = 0; i < added_subclass_to_cids.length(); i++) {
     intptr_t cid = added_subclass_to_cids[i];
     cls = class_table.At(cid);
     ASSERT(!cls.IsNull());
-    array = cls.functions();
-    const intptr_t num_functions = array.IsNull() ? 0 : array.Length();
-    for (intptr_t f = 0; f < num_functions; f++) {
-      function ^= array.At(f);
-      ASSERT(!function.IsNull());
-      if (function.HasOptimizedCode()) {
-        function.SwitchToUnoptimizedCode();
-      }
-    }
+    cls.DisableCHAOptimizedCode();
   }
 }
 
@@ -2195,7 +2183,7 @@
     CheckForLegalConstClass(cls);
   }
   if (FLAG_use_cha) {
-    RemoveOptimizedCode(added_subclass_to_cids);
+    RemoveCHAOptimizedCode(added_subclass_to_cids);
   }
 }
 
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 0b0c6f9..511daa5 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1437,8 +1437,16 @@
   const Code& target_code = Code::Handle(
       caller_code.GetStaticCallTargetCodeAt(frame->pc()));
   ASSERT(!target_code.IsNull());
-  // Since there was a reference to the target_code in the caller_code, it is
-  // not possible for the target_function's code to be disconnected.
+  if (!target_function.HasCode()) {
+    // If target code was unoptimized than the code must have been kept
+    // connected to the function.
+    ASSERT(target_code.is_optimized());
+    const Error& error =
+        Error::Handle(Compiler::CompileFunction(target_function));
+    if (!error.IsNull()) {
+      Exceptions::PropagateError(error);
+    }
+  }
   ASSERT(target_function.HasCode());
   ASSERT(target_function.raw() == target_code.function());
 
@@ -1486,6 +1494,11 @@
   uword lazy_deopt_jump = optimized_code.GetLazyDeoptPc();
   ASSERT(lazy_deopt_jump != 0);
   CodePatcher::InsertCallAt(pc, lazy_deopt_jump);
+  if (FLAG_trace_patching) {
+    const String& name = String::Handle(function.name());
+    OS::PrintErr("InsertCallAt: %" Px " to %" Px " for %s\n", pc,
+                 lazy_deopt_jump, name.ToCString());
+  }
   // Mark code as dead (do not GC its embedded objects).
   optimized_code.set_is_alive(false);
 }
@@ -1507,36 +1520,6 @@
 }
 
 
-// Returns true if the given array of cids contains the given cid.
-static bool ContainsCid(const GrowableArray<intptr_t>& cids, intptr_t cid) {
-  for (intptr_t i = 0; i < cids.length(); i++) {
-    if (cids[i] == cid) {
-      return true;
-    }
-  }
-  return false;
-}
-
-
-// Deoptimize optimized code on stack if its class is in the 'classes' array.
-void DeoptimizeIfOwner(const GrowableArray<intptr_t>& classes) {
-  DartFrameIterator iterator;
-  StackFrame* frame = iterator.NextFrame();
-  Code& optimized_code = Code::Handle();
-  while (frame != NULL) {
-    optimized_code = frame->LookupDartCode();
-    if (optimized_code.is_optimized()) {
-      const intptr_t owner_cid = Class::Handle(Function::Handle(
-          optimized_code.function()).Owner()).id();
-      if (ContainsCid(classes, owner_cid)) {
-        DeoptimizeAt(optimized_code, frame->pc());
-      }
-    }
-    frame = iterator.NextFrame();
-  }
-}
-
-
 static void CopySavedRegisters(uword saved_registers_address,
                                fpu_register_t** fpu_registers,
                                intptr_t** cpu_registers) {
diff --git a/runtime/vm/code_generator.h b/runtime/vm/code_generator.h
index 57ffb50..3931588 100644
--- a/runtime/vm/code_generator.h
+++ b/runtime/vm/code_generator.h
@@ -96,7 +96,6 @@
 
 void DeoptimizeAt(const Code& optimized_code, uword pc);
 void DeoptimizeAll();
-void DeoptimizeIfOwner(const GrowableArray<intptr_t>& classes);
 
 double DartModulo(double a, double b);
 void SinCos(double arg, double* sin_res, double* cos_res);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 9a8cadd..e8a5b4f 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -263,6 +263,7 @@
   bool is_compiled = false;
   Isolate* isolate = Isolate::Current();
   HANDLESCOPE(isolate);
+  isolate->set_cha_used(false);
 
   // We may reattempt compilation if the function needs to be assembled using
   // far branches on ARM and MIPS. In the else branch of the setjmp call,
@@ -540,6 +541,12 @@
         const Code& code = Code::Handle(
             Code::FinalizeCode(function, &assembler, optimized));
         code.set_is_optimized(optimized);
+        // CHA should not be used for unoptimized code.
+        ASSERT(optimized || !isolate->cha_used());
+        if (isolate->cha_used()) {
+          Class::Handle(function.Owner()).RegisterCHACode(code);
+          isolate->set_cha_used(false);
+        }
         graph_compiler.FinalizePcDescriptors(code);
         graph_compiler.FinalizeDeoptInfo(code);
         graph_compiler.FinalizeStackmaps(code);
diff --git a/runtime/vm/compiler_stats.cc b/runtime/vm/compiler_stats.cc
index 2a0671f..786fff9 100644
--- a/runtime/vm/compiler_stats.cc
+++ b/runtime/vm/compiler_stats.cc
@@ -61,6 +61,11 @@
 intptr_t CompilerStats::num_tokens_rewind = 0;
 intptr_t CompilerStats::num_tokens_lookahead = 0;
 
+intptr_t CompilerStats::num_lib_cache_hit = 0;
+intptr_t CompilerStats::num_names_cached = 0;
+intptr_t CompilerStats::make_accessor_name = 0;
+intptr_t CompilerStats::make_field_name = 0;
+
 void CompilerStats::Print() {
   if (!FLAG_compiler_stats) {
     return;
@@ -79,6 +84,12 @@
   OS::Print("Token lookahead:    %" Pd " (%" Pd "%% of tokens checked)\n",
             num_tokens_lookahead,
             (100 * num_tokens_lookahead) / num_token_checks);
+
+  OS::Print("Lib names cached:   %" Pd "\n", num_names_cached);
+  OS::Print("Lib name cache hit: %" Pd "\n", num_lib_cache_hit);
+  OS::Print("Accessor mangling:  %" Pd " field->acc  %" Pd " acc->field\n",
+            make_accessor_name, make_field_name);
+
   OS::Print("Source length:      %" Pd " characters\n", src_length);
   int64_t scan_usecs = scanner_timer.TotalElapsedTime();
   OS::Print("Scanner time:       %" Pd64 " msecs\n",
diff --git a/runtime/vm/compiler_stats.h b/runtime/vm/compiler_stats.h
index 363a537..57d4d65 100644
--- a/runtime/vm/compiler_stats.h
+++ b/runtime/vm/compiler_stats.h
@@ -15,7 +15,6 @@
 
 DECLARE_FLAG(bool, compiler_stats);
 
-
 class CompilerStats : AllStatic {
  public:
   static intptr_t num_tokens_total;
@@ -26,6 +25,11 @@
   static intptr_t num_tokens_rewind;
   static intptr_t num_tokens_lookahead;
 
+  static intptr_t num_lib_cache_hit;
+  static intptr_t num_names_cached;
+  static intptr_t make_accessor_name;
+  static intptr_t make_field_name;
+
   static intptr_t src_length;        // Total number of characters in source.
   static intptr_t code_allocated;    // Bytes allocated for generated code.
   static Timer parser_timer;         // Cumulative runtime of parser.
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 91d6eb7..754f0d6 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -920,6 +920,17 @@
 }
 
 
+DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate) {
+  TRACE_API_CALL(CURRENT_FUNC);
+  if (isolate == NULL) {
+    FATAL1("%s expects argument 'isolate' to be non-null.",  CURRENT_FUNC);
+  }
+  // TODO(16615): Validate isolate parameter.
+  Isolate* iso = reinterpret_cast<Isolate*>(isolate);
+  return iso->init_callback_data();
+}
+
+
 DART_EXPORT Dart_Handle Dart_DebugName() {
   Isolate* isolate = Isolate::Current();
   DARTSCOPE(isolate);
@@ -928,10 +939,11 @@
 
 
 
-DART_EXPORT void Dart_EnterIsolate(Dart_Isolate dart_isolate) {
+DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate) {
   CHECK_NO_ISOLATE(Isolate::Current());
-  Isolate* isolate = reinterpret_cast<Isolate*>(dart_isolate);
-  Isolate::SetCurrent(isolate);
+  // TODO(16615): Validate isolate parameter.
+  Isolate* iso = reinterpret_cast<Isolate*>(isolate);
+  Isolate::SetCurrent(iso);
 }
 
 
@@ -1007,6 +1019,7 @@
   if (isolate == NULL) {
     FATAL1("%s expects argument 'isolate' to be non-null.",  CURRENT_FUNC);
   }
+  // TODO(16615): Validate isolate parameter.
   Isolate* iso = reinterpret_cast<Isolate*>(isolate);
   iso->ScheduleInterrupts(Isolate::kApiInterrupt);
 }
@@ -1017,6 +1030,7 @@
   if (isolate == NULL) {
     FATAL1("%s expects argument 'isolate' to be non-null.",  CURRENT_FUNC);
   }
+  // TODO(16615): Validate isolate parameter.
   Isolate* iso = reinterpret_cast<Isolate*>(isolate);
   return iso->MakeRunnable();
 }
@@ -3059,21 +3073,25 @@
   }
   const Class& cls = Class::Handle(isolate, type_obj.type_class());
 
-  // Mark all fields as nullable.
-  Class& iterate_cls = Class::Handle(isolate, cls.raw());
-  Field& field = Field::Handle(isolate);
-  Array& fields = Array::Handle(isolate);
-  while (!iterate_cls.IsNull()) {
-    fields = iterate_cls.fields();
-    iterate_cls = iterate_cls.SuperClass();
-    for (int field_num = 0; field_num < fields.Length(); field_num++) {
-      field ^= fields.At(field_num);
-      if (field.is_static()) {
-        continue;
+  if (!cls.is_fields_marked_nullable()) {
+    // Mark all fields as nullable.
+    Class& iterate_cls = Class::Handle(isolate, cls.raw());
+    Field& field = Field::Handle(isolate);
+    Array& fields = Array::Handle(isolate);
+    while (!iterate_cls.IsNull()) {
+      iterate_cls.set_is_fields_marked_nullable();
+      fields = iterate_cls.fields();
+      iterate_cls = iterate_cls.SuperClass();
+      for (int field_num = 0; field_num < fields.Length(); field_num++) {
+        field ^= fields.At(field_num);
+        if (field.is_static()) {
+          continue;
+        }
+        field.UpdateGuardedCidAndLength(Object::null_object());
       }
-      field.UpdateGuardedCidAndLength(Object::null_object());
     }
   }
+
   // Allocate an object for the given class.
   return Api::NewHandle(isolate, Instance::New(cls));
 }
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 30b3ad5..4a7642e 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -3059,6 +3059,7 @@
                          &err);
   EXPECT(isolate != NULL);
   EXPECT_EQ(mydata, reinterpret_cast<intptr_t>(Dart_CurrentIsolateData()));
+  EXPECT_EQ(mydata, reinterpret_cast<intptr_t>(Dart_IsolateData(isolate)));
   Dart_ShutdownIsolate();
 }
 
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index bc7efff..a858a5f 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -899,7 +899,7 @@
                         const Library& library,
                         const String& fname) {
   ASSERT(!library.IsNull());
-  const Object& object = Object::Handle(library.LookupObject(fname));
+  const Object& object = Object::Handle(library.ResolveName(fname));
   if (!object.IsNull() && object.IsFunction()) {
     return Function::Cast(object).raw();
   }
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index 150e451..3981beb 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -251,6 +251,7 @@
     case 0x57: return "xorps";
     case 0x58: return "addps";
     case 0x59: return "mulps";
+    case 0x5A: return "cvtps2pd";
     case 0x5C: return "subps";
     case 0x5D: return "minps";
     case 0x5E: return "divps";
@@ -262,6 +263,23 @@
   }
 }
 
+static const char* PackedDoubleMnemonic(uint8_t data) {
+  const char* mnemonic = NULL;
+  if (data == 0xFE) mnemonic = "paddd ";
+  if (data == 0xFA) mnemonic = "psubd ";
+  if (data == 0x2F) mnemonic = "comisd ";
+  if (data == 0x58) mnemonic = "addpd ";
+  if (data == 0x5C) mnemonic = "subpd ";
+  if (data == 0x59) mnemonic = "mulpd ";
+  if (data == 0x5E) mnemonic = "divpd ";
+  if (data == 0x5D) mnemonic = "minpd ";
+  if (data == 0x5F) mnemonic = "maxpd ";
+  if (data == 0x51) mnemonic = "sqrtpd ";
+  if (data == 0x5A) mnemonic = "cvtpd2ps ";
+  ASSERT(mnemonic != NULL);
+  return mnemonic;
+}
+
 
 static bool IsTwoXmmRegInstruction(uint8_t f0byte) {
   return f0byte == 0x28 || f0byte == 0x11 || f0byte == 0x12 ||
@@ -269,7 +287,7 @@
          f0byte == 0x51 || f0byte == 0x52 || f0byte == 0x53 ||
          f0byte == 0x54 || f0byte == 0x56 || f0byte == 0x58 ||
          f0byte == 0x59 || f0byte == 0x5C || f0byte == 0x5D ||
-         f0byte == 0x5E || f0byte == 0x5F;
+         f0byte == 0x5E || f0byte == 0x5F || f0byte == 0x5A;
 }
 
 
@@ -1602,11 +1620,11 @@
             Print(",");
             PrintXmmRegister(rm);
             data += 2;
-          } else if ((*data == 0xFE) || (*data == 0xFA) || (*data == 0x2F)) {
-            const char* mnemonic = NULL;
-            if (*data == 0xFE) mnemonic = "paddd ";
-            if (*data == 0xFA) mnemonic = "psubd ";
-            if (*data == 0x2F) mnemonic = "comisd ";
+          } else if ((*data == 0xFE) || (*data == 0xFA) || (*data == 0x2F) ||
+                     (*data == 0x58) || (*data == 0x5C) || (*data == 0x59) ||
+                     (*data == 0x5E) || (*data == 0x5D) || (*data == 0x5F) ||
+                     (*data == 0x51) || (*data == 0x5A)) {
+            const char* mnemonic = PackedDoubleMnemonic(*data);
             int mod, regop, rm;
             GetModRm(*(data+1), &mod, &regop, &rm);
             Print(mnemonic);
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 86f8d25..4d58672 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -1287,6 +1287,22 @@
           mnemonic = "paddd";
         } else if (opcode == 0xFA) {
           mnemonic = "psubd";
+        } else if (opcode == 0x58) {
+          mnemonic = "addpd";
+        } else if (opcode == 0x5C) {
+          mnemonic = "subpd";
+        } else if (opcode == 0x59) {
+          mnemonic = "mulpd";
+        } else if (opcode == 0x5E) {
+          mnemonic = "divpd";
+        } else if (opcode == 0x5D) {
+          mnemonic = "minpd";
+        } else if (opcode == 0x5F) {
+          mnemonic = "maxpd";
+        } else if (opcode == 0x51) {
+          mnemonic = "sqrtpd";
+        } else if (opcode == 0x5A) {
+          mnemonic = "cvtpd2ps";
         } else {
           UnimplementedInstruction();
         }
@@ -1379,6 +1395,11 @@
       get_modrm(*current, &mod, &regop, &rm);
       AppendToBuffer("movq %s, ", NameOfXMMRegister(regop));
       current += PrintRightXMMOperand(current);
+    } else if (opcode == 0x58) {
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
+      current += PrintRightXMMOperand(current);
     } else {
       UnimplementedInstruction();
     }
@@ -1552,6 +1573,10 @@
       return "movsxb";
     case 0xBF:
       return "movsxw";
+    case 0x12:
+      return "movhlps";
+    case 0x16:
+      return "movlhps";
     default:
       return NULL;
   }
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index f5678b7..d716b25 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2173,14 +2173,15 @@
       AbstractTypeArguments::ZoneHandle(node->type().arguments());
   Value* element_type = BuildInstantiatedTypeArguments(node->token_pos(),
                                                        type_args);
+  Value* num_elements =
+      Bind(new ConstantInstr(Smi::ZoneHandle(Smi::New(node->length()))));
   CreateArrayInstr* create = new CreateArrayInstr(node->token_pos(),
-                                                  node->length(),
-                                                  node->type(),
-                                                  element_type);
+                                                  element_type,
+                                                  num_elements);
   Value* array_val = Bind(create);
 
   { LocalVariable* tmp_var = EnterTempLocalScope(array_val);
-    const intptr_t class_id = create->Type()->ToCid();
+    const intptr_t class_id = kArrayCid;
     const intptr_t deopt_id = Isolate::kNoDeoptId;
     for (int i = 0; i < node->length(); ++i) {
       Value* array = Bind(new LoadLocalInstr(*tmp_var));
@@ -2553,32 +2554,6 @@
 }
 
 
-// Class that recognizes factories and returns corresponding result cid.
-class FactoryRecognizer : public AllStatic {
- public:
-  // Return kDynamicCid if factory is not recognized.
-  static intptr_t ResultCid(const Function& factory) {
-    ASSERT(factory.IsFactory());
-    const Class& function_class = Class::Handle(factory.Owner());
-    const Library& lib = Library::Handle(function_class.library());
-    ASSERT((lib.raw() == Library::CoreLibrary()) ||
-        (lib.raw() == Library::TypedDataLibrary()));
-    const String& factory_name = String::Handle(factory.name());
-#define RECOGNIZE_FACTORY(test_factory_symbol, cid, fp)                        \
-    if (String::EqualsIgnoringPrivateKey(                                      \
-        factory_name, Symbols::test_factory_symbol())) {                       \
-      ASSERT(factory.CheckSourceFingerprint(fp));                              \
-      return cid;                                                              \
-    }                                                                          \
-
-RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY);
-#undef RECOGNIZE_FACTORY
-
-    return kDynamicCid;
-  }
-};
-
-
 static intptr_t GetResultCidOfListFactory(ConstructorCallNode* node) {
   const Function& function = node->constructor();
   const Class& function_class = Class::Handle(function.Owner());
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index ead8e24..b527bff 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -49,6 +49,32 @@
   V(_Float32x4ArrayFactory, kTypedDataFloat32x4ArrayCid, 879975401)            \
 
 
+// Class that recognizes factories and returns corresponding result cid.
+class FactoryRecognizer : public AllStatic {
+ public:
+  // Return kDynamicCid if factory is not recognized.
+  static intptr_t ResultCid(const Function& factory) {
+    ASSERT(factory.IsFactory());
+    const Class& function_class = Class::Handle(factory.Owner());
+    const Library& lib = Library::Handle(function_class.library());
+    ASSERT((lib.raw() == Library::CoreLibrary()) ||
+        (lib.raw() == Library::TypedDataLibrary()));
+    const String& factory_name = String::Handle(factory.name());
+#define RECOGNIZE_FACTORY(test_factory_symbol, cid, fp)                        \
+    if (String::EqualsIgnoringPrivateKey(                                      \
+        factory_name, Symbols::test_factory_symbol())) {                       \
+      ASSERT(factory.CheckSourceFingerprint(fp));                              \
+      return cid;                                                              \
+    }                                                                          \
+
+RECOGNIZED_LIST_FACTORY_LIST(RECOGNIZE_FACTORY);
+#undef RECOGNIZE_FACTORY
+
+    return kDynamicCid;
+  }
+};
+
+
 // A class to collect the exits from an inlined function during graph
 // construction so they can be plugged into the caller's flow graph.
 class InlineExitCollector: public ZoneAllocated {
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 41c43b6..91ff5fe 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -26,6 +26,8 @@
 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function");
 
 // Flags for inlining heuristics.
+DEFINE_FLAG(int, inline_getters_setters_smaller_than, 10,
+    "Always inline getters and setters that have fewer instructions");
 DEFINE_FLAG(int, inlining_depth_threshold, 3,
     "Inline function calls up to threshold nesting depth");
 DEFINE_FLAG(int, inlining_size_threshold, 25,
@@ -271,9 +273,7 @@
         }
         StaticCallInstr* static_call = current->AsStaticCall();
         if (static_call != NULL) {
-          if (static_call->function().IsInlineable()) {
-            static_calls_.Add(StaticCallInfo(static_call));
-          }
+          static_calls_.Add(StaticCallInfo(static_call));
           continue;
         }
         PolymorphicInstanceCallInstr* instance_call =
@@ -365,7 +365,8 @@
       // Prevent methods becoming humongous and thus slow to compile.
       return false;
     }
-    if (instr_count <= FLAG_inlining_size_threshold) {
+    // 'instr_count' can be 0 if it was not computed yet.
+    if ((instr_count != 0) && (instr_count <= FLAG_inlining_size_threshold)) {
       return true;
     }
     if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) {
@@ -375,7 +376,7 @@
         (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) {
       return true;
     }
-    if (MethodRecognizer::AlwaysInline(callee)) {
+    if (FlowGraphInliner::AlwaysInline(callee)) {
       return true;
     }
     return false;
@@ -777,7 +778,7 @@
         }
       }
       const Function& target = call->function();
-      if (!MethodRecognizer::AlwaysInline(target) &&
+      if (!FlowGraphInliner::AlwaysInline(target) &&
           (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
         TRACE_INLINING(OS::Print(
             "  => %s (deopt count %d)\n     Bailout: cold %f\n",
@@ -849,7 +850,7 @@
 
       const ICData& ic_data = call->ic_data();
       const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
-      if (!MethodRecognizer::AlwaysInline(target) &&
+      if (!FlowGraphInliner::AlwaysInline(target) &&
           (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
         TRACE_INLINING(OS::Print(
             "  => %s (deopt count %d)\n     Bailout: cold %f\n",
@@ -1448,6 +1449,18 @@
 }
 
 
+bool FlowGraphInliner::AlwaysInline(const Function& function) {
+  if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
+      function.IsImplicitSetterFunction() || function.IsSetterFunction()) {
+    const intptr_t count = function.optimized_instruction_count();
+    if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) {
+      return true;
+    }
+  }
+  return MethodRecognizer::AlwaysInline(function);
+}
+
+
 void FlowGraphInliner::Inline() {
   // Collect graph info and store it on the function.
   // We might later use it for an early bailout from the inlining.
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index dfee0d5..e408d92 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -11,6 +11,7 @@
 
 class Field;
 class FlowGraph;
+class Function;
 template <typename T> class GrowableArray;
 
 class FlowGraphInliner : ValueObject {
@@ -22,6 +23,8 @@
 
   static void CollectGraphInfo(FlowGraph* flow_graph);
 
+  static bool AlwaysInline(const Function& function);
+
  private:
   FlowGraph* flow_graph_;
 
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 83d9045..2c7c516 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -354,10 +354,12 @@
           (other_binop->right()->definition() == right_def)) {
         (*merge_candidates)[k] = NULL;  // Clear it.
         // Append a LoadIndexed behind TRUNC_DIV and MOD.
+        ASSERT(curr_instr->HasUses());
         AppendLoadIndexedForMerged(
             curr_instr,
             MergedMathInstr::ResultIndexOf(curr_instr->op_kind()),
             kArrayCid);
+        ASSERT(other_binop->HasUses());
         AppendLoadIndexedForMerged(
             other_binop,
             MergedMathInstr::ResultIndexOf(other_binop->op_kind()),
@@ -414,10 +416,12 @@
           (other_op->value()->definition() == def)) {
         (*merge_candidates)[k] = NULL;  // Clear it.
         // Append a LoadIndexed behind SIN and COS.
+        ASSERT(curr_instr->HasUses());
         AppendLoadIndexedForMerged(
             curr_instr,
             MergedMathInstr::ResultIndexOf(curr_instr->kind()),
             kTypedDataFloat64ArrayCid);
+        ASSERT(other_op->HasUses());
         AppendLoadIndexedForMerged(
             other_op,
             MergedMathInstr::ResultIndexOf(other_op->kind()),
@@ -467,7 +471,9 @@
                                        binop->right()->definition());
         } else if ((binop->op_kind() == Token::kTRUNCDIV) ||
                    (binop->op_kind() == Token::kMOD)) {
-          div_mod_merge.Add(binop);
+          if (binop->HasUses()) {
+            div_mod_merge.Add(binop);
+          }
         }
       } else if (it.Current()->IsBinaryMintOp()) {
         BinaryMintOpInstr* mintop = it.Current()->AsBinaryMintOp();
@@ -480,7 +486,9 @@
         MathUnaryInstr* math_unary = it.Current()->AsMathUnary();
         if ((math_unary->kind() == MethodRecognizer::kMathSin) ||
             (math_unary->kind() == MethodRecognizer::kMathCos)) {
-          sin_cos_merge.Add(math_unary);
+          if (math_unary->HasUses()) {
+            sin_cos_merge.Add(math_unary);
+          }
         }
       }
     }
@@ -3680,6 +3688,31 @@
     ConstantInstr* cid_instr = new ConstantInstr(Smi::Handle(Smi::New(cid)));
     ReplaceCall(call, cid_instr);
   }
+
+  if (call->function().IsFactory()) {
+    const Class& function_class = Class::Handle(call->function().Owner());
+    if ((function_class.library() == Library::CoreLibrary()) ||
+        (function_class.library() == Library::TypedDataLibrary())) {
+      intptr_t cid = FactoryRecognizer::ResultCid(call->function());
+      switch (cid) {
+        case kArrayCid: {
+          Value* type = new Value(call->ArgumentAt(0));
+          Value* num_elements = new Value(call->ArgumentAt(1));
+          if (num_elements->BindsToConstant() &&
+              num_elements->BoundConstant().IsSmi()) {
+            intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
+            if (length >= 0 && length <= Array::kMaxElements) {
+              CreateArrayInstr* create_array =
+                  new CreateArrayInstr(call->token_pos(), type, num_elements);
+              ReplaceCall(call, create_array);
+            }
+          }
+        }
+        default:
+          break;
+      }
+    }
+  }
 }
 
 
@@ -7119,11 +7152,15 @@
 void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) {
   if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
       (instr->instance()->definition()->IsCreateArray())) {
-    const intptr_t length =
+    Value* num_elements =
         instr->instance()->definition()->AsCreateArray()->num_elements();
-    const Object& result = Smi::ZoneHandle(Smi::New(length));
-    SetValue(instr, result);
-    return;
+    if (num_elements->BindsToConstant() &&
+        num_elements->BoundConstant().IsSmi()) {
+      intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
+      const Object& result = Smi::ZoneHandle(Smi::New(length));
+      SetValue(instr, result);
+      return;
+    }
   }
 
   if (instr->IsImmutableLengthLoad()) {
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 8ad89cc..99a92bb 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -96,7 +96,9 @@
         BranchInstr* branch = instr->AsBranch();
         if (branch != NULL) {
           ConstrainedCompileType* constrained_type = branch->constrained_type();
-          if (constrained_type != NULL) constrained_type->Update();
+          if (constrained_type != NULL) {
+            constrained_type->Update();
+          }
         }
       }
     }
@@ -225,7 +227,7 @@
 ConstrainedCompileType* FlowGraphTypePropagator::MarkNonNullable(
     Definition* def) {
   CompileType* current = TypeOf(def);
-  if (current->is_nullable()) {
+  if (current->is_nullable() && (current->ToCid() != kNullCid)) {
     ConstrainedCompileType* constrained_type =
         new NotNullConstrainedCompileType(current);
     SetTypeOf(def, constrained_type->ToCompileType());
@@ -512,7 +514,7 @@
       if (FLAG_use_cha || IsKnownPrivateClass(type_class)) {
         // A known private class cannot be subclassed or implemented.
         if (!type_class.is_implemented() &&
-            !CHA::HasSubclasses(type_class.id())) {
+            !CHA::HasSubclassesSafe(type_class.id())) {
           cid_ = type_class.id();
         } else {
           cid_ = kDynamicCid;
@@ -922,7 +924,8 @@
 
 
 CompileType CreateArrayInstr::ComputeType() const {
-  return CompileType::FromAbstractType(type(), CompileType::kNonNullable);
+  // TODO(fschneider): Add abstract type and type arguments to the compile type.
+  return CompileType::FromCid(kArrayCid);
 }
 
 
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index ba68b52..4ec778a 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -151,6 +151,21 @@
 }
 
 
+Representation LoadFieldInstr::representation() const {
+  if (IsUnboxedLoad()) {
+    const intptr_t cid = field()->UnboxedFieldCid();
+    switch (cid) {
+      case kDoubleCid:
+        return kUnboxedDouble;
+      // TODO(johnmccutchan): Add kFloat32x4Cid here.
+      default:
+        UNREACHABLE();
+    }
+  }
+  return kTagged;
+}
+
+
 bool StoreInstanceFieldInstr::IsUnboxedStore() const {
   return FLAG_unbox_double_fields && field().IsUnboxedField();
 }
@@ -161,6 +176,22 @@
 }
 
 
+Representation StoreInstanceFieldInstr::RequiredInputRepresentation(
+  intptr_t index) const {
+  ASSERT((index == 0) || (index == 1));
+  if ((index == 1) && IsUnboxedStore()) {
+    const intptr_t cid = field().UnboxedFieldCid();
+    switch (cid) {
+      case kDoubleCid:
+        return kUnboxedDouble;
+      default:
+        UNREACHABLE();
+    }
+  }
+  return kTagged;
+}
+
+
 bool GuardFieldInstr::AttributesEqual(Instruction* other) const {
   return field().raw() == other->AsGuardField()->field().raw();
 }
@@ -408,11 +439,6 @@
 
 
 bool MethodRecognizer::AlwaysInline(const Function& function) {
-  if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
-      function.IsImplicitSetterFunction() || function.IsSetterFunction()) {
-    return true;
-  }
-
   const Class& function_class = Class::Handle(function.Owner());
   const Library& lib = Library::Handle(function_class.library());
   if (!IsRecognizedLibrary(lib)) {
@@ -1388,6 +1414,14 @@
 }
 
 
+// A math unary instruction has a side effect (exception
+// thrown) if the argument is not a number.
+// TODO(srdjan): eliminate if has no uses and input is guaranteed to be number.
+Definition* MathUnaryInstr::Canonicalize(FlowGraph* flow_graph) {
+  return this;
+}
+
+
 Definition* LoadFieldInstr::Canonicalize(FlowGraph* flow_graph) {
   if (!HasUses()) return NULL;
   if (!IsImmutableLengthLoad()) return this;
@@ -2917,8 +2951,14 @@
   CreateArrayInstr* create_array = value()->definition()->AsCreateArray();
   ASSERT(create_array != NULL);
   // Check if the string interpolation has only constant inputs.
-  GrowableArray<ConstantInstr*> constants(create_array->num_elements());
-  for (intptr_t i = 0; i < create_array->num_elements(); i++) {
+  Value* num_elements = create_array->num_elements();
+  if (!num_elements->BindsToConstant() ||
+      !num_elements->BoundConstant().IsSmi()) {
+    return this;
+  }
+  intptr_t length = Smi::Cast(num_elements->BoundConstant()).Value();
+  GrowableArray<ConstantInstr*> constants(length);
+  for (intptr_t i = 0; i < length; i++) {
     constants.Add(NULL);
   }
   for (Value::Iterator it(create_array->input_use_list());
@@ -2944,7 +2984,7 @@
   }
   // Interpolate string at compile time.
   const Array& array_argument =
-      Array::Handle(Array::New(create_array->num_elements()));
+      Array::Handle(Array::New(length));
   for (intptr_t i = 0; i < constants.length(); i++) {
     array_argument.SetAt(i, constants[i]->value());
   }
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index d3959f3..1b63f7a 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -3509,11 +3509,7 @@
 
   bool IsPotentialUnboxedStore() const;
 
-  virtual Representation RequiredInputRepresentation(intptr_t index) const {
-    ASSERT((index == 0) || (index == 1));
-    if ((index == 1) && IsUnboxedStore()) return kUnboxedDouble;
-    return kTagged;
-  }
+  virtual Representation RequiredInputRepresentation(intptr_t index) const;
 
  private:
   friend class FlowGraphOptimizer;  // For ASSERT(initialization_).
@@ -4095,29 +4091,28 @@
 };
 
 
-class CreateArrayInstr : public TemplateDefinition<1> {
+class CreateArrayInstr : public TemplateDefinition<2> {
  public:
   CreateArrayInstr(intptr_t token_pos,
-                   intptr_t num_elements,
-                   const AbstractType& type,
-                   Value* element_type)
-      : token_pos_(token_pos),
-        num_elements_(num_elements),
-        type_(type) {
-    ASSERT(type_.IsZoneHandle());
-    ASSERT(!type_.IsNull());
-    ASSERT(type_.IsFinalized());
-    SetInputAt(0, element_type);
+                   Value* element_type,
+                   Value* num_elements)
+      : token_pos_(token_pos) {
+    SetInputAt(kElementTypePos, element_type);
+    SetInputAt(kLengthPos, num_elements);
   }
 
+  enum {
+    kElementTypePos = 0,
+    kLengthPos = 1
+  };
+
   DECLARE_INSTRUCTION(CreateArray)
   virtual CompileType ComputeType() const;
 
-  intptr_t num_elements() const { return num_elements_; }
 
   intptr_t token_pos() const { return token_pos_; }
-  const AbstractType& type() const { return type_; }
-  Value* element_type() const { return inputs_[0]; }
+  Value* element_type() const { return inputs_[kElementTypePos]; }
+  Value* num_elements() const { return inputs_[kLengthPos]; }
 
   virtual void PrintOperandsTo(BufferFormatter* f) const;
 
@@ -4129,8 +4124,6 @@
 
  private:
   const intptr_t token_pos_;
-  const intptr_t num_elements_;
-  const AbstractType& type_;
 
   DISALLOW_COPY_AND_ASSIGN(CreateArrayInstr);
 };
@@ -4263,9 +4256,7 @@
   const Field* field() const { return field_; }
   void set_field(const Field* field) { field_ = field; }
 
-  virtual Representation representation() const {
-    return IsUnboxedLoad() ? kUnboxedDouble : kTagged;
-  }
+  virtual Representation representation() const;
 
   bool IsUnboxedLoad() const;
 
@@ -4918,6 +4909,8 @@
 
   virtual bool MayThrow() const { return false; }
 
+  Definition* Canonicalize(FlowGraph* flow_graph);
+
  private:
   const MethodRecognizer::Kind kind_;
 
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index bb286e3..977763a 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -1583,16 +1583,16 @@
 
 class StoreInstanceFieldSlowPath : public SlowPathCode {
  public:
-  explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
-      : instruction_(instruction) { }
+  StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+                             const Class& cls)
+      : instruction_(instruction), cls_(cls) { }
 
   virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
     __ Comment("StoreInstanceFieldSlowPath");
     __ Bind(entry_label());
-    const Class& double_class = compiler->double_class();
     const Code& stub =
-        Code::Handle(StubCode::GetAllocationStubForClass(double_class));
-    const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+        Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+    const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
 
     LocationSummary* locs = instruction_->locs();
     locs->live_registers()->Remove(locs->out());
@@ -1610,6 +1610,7 @@
 
  private:
   StoreInstanceFieldInstr* instruction_;
+  const Class& cls_;
 };
 
 
@@ -1653,12 +1654,22 @@
     DRegister value = EvenDRegisterOf(locs()->in(1).fpu_reg());
     Register temp = locs()->temp(0).reg();
     Register temp2 = locs()->temp(1).reg();
+    const intptr_t cid = field().UnboxedFieldCid();
 
     if (is_initialization_) {
+      const Class* cls = NULL;
+      switch (cid) {
+        case kDoubleCid:
+          cls = &compiler->double_class();
+          break;
+        // TODO(johnmccutchan): Add kFloat32x4Cid here.
+        default:
+          UNREACHABLE();
+      }
       StoreInstanceFieldSlowPath* slow_path =
-          new StoreInstanceFieldSlowPath(this);
+          new StoreInstanceFieldSlowPath(this, *cls);
       compiler->AddSlowPathCode(slow_path);
-      __ TryAllocate(compiler->double_class(),
+      __ TryAllocate(*cls,
                      slow_path->entry_label(),
                      temp,
                      temp2);
@@ -1670,7 +1681,15 @@
     } else {
       __ ldr(temp, FieldAddress(instance_reg, field().Offset()));
     }
-    __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+    switch (cid) {
+      case kDoubleCid:
+      __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+      // TODO(johnmccutchan): Add kFloat32x4Cid here.
+      break;
+      default:
+        UNREACHABLE();
+    }
+
     return;
   }
 
@@ -1680,25 +1699,36 @@
     Register temp2 = locs()->temp(1).reg();
     DRegister fpu_temp = EvenDRegisterOf(locs()->temp(2).fpu_reg());
 
-    Label store_pointer, copy_payload;
+    Label store_pointer;
+    Label copy_double;
+    Label store_double;
+
     __ LoadObject(temp, Field::ZoneHandle(field().raw()));
-    __ ldr(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
-    __ CompareImmediate(temp2, kDoubleCid);
-    __ b(&store_pointer, NE);
+
     __ ldr(temp2, FieldAddress(temp, Field::is_nullable_offset()));
     __ CompareImmediate(temp2, kNullCid);
     __ b(&store_pointer, EQ);
+
     __ ldrb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
     __ tst(temp2, ShifterOperand(1 << Field::kUnboxingCandidateBit));
     __ b(&store_pointer, EQ);
 
+    __ ldr(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
+    __ CompareImmediate(temp2, kDoubleCid);
+    __ b(&store_double, EQ);
+
+    // Fall through.
+    __ b(&store_pointer);
+
+    __ Bind(&store_double);
+
     __ ldr(temp, FieldAddress(instance_reg, field().Offset()));
     __ CompareImmediate(temp,
                         reinterpret_cast<intptr_t>(Object::null()));
-    __ b(&copy_payload, NE);
+    __ b(&copy_double, NE);
 
     StoreInstanceFieldSlowPath* slow_path =
-        new StoreInstanceFieldSlowPath(this);
+        new StoreInstanceFieldSlowPath(this, compiler->double_class());
     compiler->AddSlowPathCode(slow_path);
 
     if (!compiler->is_optimizing()) {
@@ -1715,7 +1745,7 @@
     __ StoreIntoObject(instance_reg,
                        FieldAddress(instance_reg, field().Offset()),
                        temp2);
-    __ Bind(&copy_payload);
+    __ Bind(&copy_double);
     __ LoadDFromOffset(fpu_temp,
                        value_reg,
                        Double::value_offset() - kHeapObjectTag);
@@ -1822,11 +1852,12 @@
 
 
 LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
-  const intptr_t kNumInputs = 1;
+  const intptr_t kNumInputs = 2;
   const intptr_t kNumTemps = 0;
   LocationSummary* locs =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
-  locs->set_in(0, Location::RegisterLocation(R1));
+  locs->set_in(kElementTypePos, Location::RegisterLocation(R1));
+  locs->set_in(kLengthPos, Location::RegisterLocation(R2));
   locs->set_out(Location::RegisterLocation(R0));
   return locs;
 }
@@ -1834,8 +1865,8 @@
 
 void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // Allocate the array.  R2 = length, R1 = element type.
-  ASSERT(locs()->in(0).reg() == R1);
-  __ LoadImmediate(R2, Smi::RawValue(num_elements()));
+  ASSERT(locs()->in(kElementTypePos).reg() == R1);
+  ASSERT(locs()->in(kLengthPos).reg() == R2);
   compiler->GenerateCall(token_pos(),
                          &StubCode::AllocateArrayLabel(),
                          PcDescriptors::kOther,
@@ -1925,7 +1956,16 @@
     DRegister result = EvenDRegisterOf(locs()->out().fpu_reg());
     Register temp = locs()->temp(0).reg();
     __ ldr(temp, FieldAddress(instance_reg, offset_in_bytes()));
-    __ LoadDFromOffset(result, temp, Double::value_offset() - kHeapObjectTag);
+    intptr_t cid = field()->UnboxedFieldCid();
+    switch (cid) {
+      case kDoubleCid:
+        __ LoadDFromOffset(result, temp,
+                           Double::value_offset() - kHeapObjectTag);
+        break;
+      // TODO(johnmccutchan): Add Float32x4 path here.
+      default:
+        UNREACHABLE();
+    }
     return;
   }
 
@@ -1936,20 +1976,27 @@
     DRegister value = EvenDRegisterOf(locs()->temp(0).fpu_reg());
 
     Label load_pointer;
+    Label load_double;
+
     __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
 
     FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(result_reg,
                                            Field::is_nullable_offset());
 
-    __ ldr(temp, field_cid_operand);
-    __ CompareImmediate(temp, kDoubleCid);
-    __ b(&load_pointer, NE);
-
     __ ldr(temp, field_nullability_operand);
     __ CompareImmediate(temp, kNullCid);
     __ b(&load_pointer, EQ);
 
+    __ ldr(temp, field_cid_operand);
+    __ CompareImmediate(temp, kDoubleCid);
+    __ b(&load_double, EQ);
+
+    // Fall through.
+    __ b(&load_pointer);
+
+    __ Bind(&load_double);
+
     BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
     compiler->AddSlowPathCode(slow_path);
 
@@ -1968,6 +2015,9 @@
                       result_reg,
                       Double::value_offset() - kHeapObjectTag);
     __ b(&done);
+
+    // TODO(johnmccutchan): Add Float32x4 path here.
+
     __ Bind(&load_pointer);
   }
   __ LoadFromOffset(kWord, result_reg,
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 50075ba..c1b3e04 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -1592,16 +1592,16 @@
 
 class StoreInstanceFieldSlowPath : public SlowPathCode {
  public:
-  explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
-      : instruction_(instruction) { }
+  StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+                             const Class& cls)
+      : instruction_(instruction), cls_(cls) { }
 
   virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
     __ Comment("StoreInstanceFieldSlowPath");
     __ Bind(entry_label());
-    const Class& double_class = compiler->double_class();
     const Code& stub =
-        Code::Handle(StubCode::GetAllocationStubForClass(double_class));
-    const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+        Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+    const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
 
     LocationSummary* locs = instruction_->locs();
     locs->live_registers()->Remove(locs->out());
@@ -1619,6 +1619,7 @@
 
  private:
   StoreInstanceFieldInstr* instruction_;
+  const Class& cls_;
 };
 
 
@@ -1662,13 +1663,23 @@
     XmmRegister value = locs()->in(1).fpu_reg();
     Register temp = locs()->temp(0).reg();
     Register temp2 = locs()->temp(1).reg();
+    const intptr_t cid = field().UnboxedFieldCid();
 
     if (is_initialization_) {
+      const Class* cls = NULL;
+      switch (cid) {
+        case kDoubleCid:
+          cls = &compiler->double_class();
+          break;
+        // TODO(johnmccutchan): Add kFloat32x4Cid here.
+        default:
+          UNREACHABLE();
+      }
       StoreInstanceFieldSlowPath* slow_path =
-          new StoreInstanceFieldSlowPath(this);
+          new StoreInstanceFieldSlowPath(this, *cls);
       compiler->AddSlowPathCode(slow_path);
 
-      __ TryAllocate(compiler->double_class(),
+      __ TryAllocate(*cls,
                      slow_path->entry_label(),
                      Assembler::kFarJump,
                      temp,
@@ -1681,7 +1692,14 @@
     } else {
       __ movl(temp, FieldAddress(instance_reg, field().Offset()));
     }
-    __ movsd(FieldAddress(temp, Double::value_offset()), value);
+    switch (cid) {
+      case kDoubleCid:
+      __ movsd(FieldAddress(temp, Double::value_offset()), value);
+      // TODO(johnmccutchan): Add kFloat32x4Cid here.
+      break;
+      default:
+        UNREACHABLE();
+    }
     return;
   }
 
@@ -1691,26 +1709,37 @@
     Register temp2 = locs()->temp(1).reg();
     FpuRegister fpu_temp = locs()->temp(2).fpu_reg();
 
-    Label store_pointer, copy_payload;
+    Label store_pointer;
+    Label copy_double;
+    Label store_double;
+
     __ LoadObject(temp, Field::ZoneHandle(field().raw()));
-    __ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
-            Immediate(kDoubleCid));
-    __ j(NOT_EQUAL, &store_pointer);
+
     __ cmpl(FieldAddress(temp, Field::is_nullable_offset()),
             Immediate(kNullCid));
     __ j(EQUAL, &store_pointer);
+
     __ movzxb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
     __ testl(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
     __ j(ZERO, &store_pointer);
 
+    __ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
+            Immediate(kDoubleCid));
+    __ j(EQUAL, &store_double);
+
+    // Fall through.
+    __ jmp(&store_pointer);
+
+    __ Bind(&store_double);
+
     const Immediate& raw_null =
         Immediate(reinterpret_cast<intptr_t>(Object::null()));
     __ movl(temp, FieldAddress(instance_reg, field().Offset()));
     __ cmpl(temp, raw_null);
-    __ j(NOT_EQUAL, &copy_payload);
+    __ j(NOT_EQUAL, &copy_double);
 
     StoreInstanceFieldSlowPath* slow_path =
-        new StoreInstanceFieldSlowPath(this);
+        new StoreInstanceFieldSlowPath(this, compiler->double_class());
     compiler->AddSlowPathCode(slow_path);
 
     if (!compiler->is_optimizing()) {
@@ -1729,7 +1758,7 @@
                        FieldAddress(instance_reg, field().Offset()),
                        temp2);
 
-    __ Bind(&copy_payload);
+    __ Bind(&copy_double);
     __ movsd(fpu_temp, FieldAddress(value_reg, Double::value_offset()));
     __ movsd(FieldAddress(temp, Double::value_offset()), fpu_temp);
     __ jmp(&skip_store);
@@ -1835,11 +1864,12 @@
 
 
 LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
-  const intptr_t kNumInputs = 1;
+  const intptr_t kNumInputs = 2;
   const intptr_t kNumTemps = 0;
   LocationSummary* locs =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
   locs->set_in(0, Location::RegisterLocation(ECX));
+  locs->set_in(1, Location::RegisterLocation(EDX));
   locs->set_out(Location::RegisterLocation(EAX));
   return locs;
 }
@@ -1848,7 +1878,7 @@
 void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // Allocate the array.  EDX = length, ECX = element type.
   ASSERT(locs()->in(0).reg() == ECX);
-  __ movl(EDX, Immediate(Smi::RawValue(num_elements())));
+  ASSERT(locs()->in(1).reg() == EDX);
   compiler->GenerateCall(token_pos(),
                          &StubCode::AllocateArrayLabel(),
                          PcDescriptors::kOther,
@@ -1938,7 +1968,15 @@
     XmmRegister result = locs()->out().fpu_reg();
     Register temp = locs()->temp(0).reg();
     __ movl(temp, FieldAddress(instance_reg, offset_in_bytes()));
-    __ movsd(result, FieldAddress(temp, Double::value_offset()));
+    const intptr_t cid = field()->UnboxedFieldCid();
+    switch (cid) {
+      case kDoubleCid:
+        __ movsd(result, FieldAddress(temp, Double::value_offset()));
+        break;
+      // TODO(johnmccutchan): Add Float32x4 path here.
+      default:
+        UNREACHABLE();
+    }
     return;
   }
 
@@ -1949,17 +1987,22 @@
     XmmRegister value = locs()->temp(0).fpu_reg();
 
     Label load_pointer;
+    Label load_double;
     __ LoadObject(result, Field::ZoneHandle(field()->raw()));
 
     FieldAddress field_cid_operand(result, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(result, Field::is_nullable_offset());
 
-    __ cmpl(field_cid_operand, Immediate(kDoubleCid));
-    __ j(NOT_EQUAL, &load_pointer);
-
     __ cmpl(field_nullability_operand, Immediate(kNullCid));
     __ j(EQUAL, &load_pointer);
 
+    __ cmpl(field_cid_operand, Immediate(kDoubleCid));
+    __ j(EQUAL, &load_double);
+
+    // Fall through.
+    __ jmp(&load_pointer);
+
+    __ Bind(&load_double);
     BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
     compiler->AddSlowPathCode(slow_path);
 
@@ -1977,6 +2020,9 @@
     __ movsd(value, FieldAddress(temp, Double::value_offset()));
     __ movsd(FieldAddress(result, Double::value_offset()), value);
     __ jmp(&done);
+
+    // TODO(johnmccutchan): Add Float32x4 path here.
+
     __ Bind(&load_pointer);
   }
   __ movl(result, FieldAddress(instance_reg, offset_in_bytes()));
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 94d1ee5..450c24b 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -1658,16 +1658,16 @@
 
 class StoreInstanceFieldSlowPath : public SlowPathCode {
  public:
-  explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
-      : instruction_(instruction) { }
+  StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+                             const Class& cls)
+      : instruction_(instruction), cls_(cls) { }
 
   virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
     __ Comment("StoreInstanceFieldSlowPath");
     __ Bind(entry_label());
-    const Class& double_class = compiler->double_class();
     const Code& stub =
-        Code::Handle(StubCode::GetAllocationStubForClass(double_class));
-    const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+        Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+    const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
 
     LocationSummary* locs = instruction_->locs();
     locs->live_registers()->Remove(locs->out());
@@ -1685,6 +1685,7 @@
 
  private:
   StoreInstanceFieldInstr* instruction_;
+  const Class& cls_;
 };
 
 
@@ -1728,12 +1729,21 @@
     DRegister value = locs()->in(1).fpu_reg();
     Register temp = locs()->temp(0).reg();
     Register temp2 = locs()->temp(1).reg();
+    const intptr_t cid = field().UnboxedFieldCid();
 
     if (is_initialization_) {
+      const Class* cls = NULL;
+      switch (cid) {
+        case kDoubleCid:
+          cls = &compiler->double_class();
+          break;
+        default:
+          UNREACHABLE();
+      }
       StoreInstanceFieldSlowPath* slow_path =
-          new StoreInstanceFieldSlowPath(this);
+          new StoreInstanceFieldSlowPath(this, *cls);
       compiler->AddSlowPathCode(slow_path);
-      __ TryAllocate(compiler->double_class(),
+      __ TryAllocate(*cls,
                      slow_path->entry_label(),
                      temp,
                      temp2);
@@ -1745,7 +1755,13 @@
     } else {
       __ lw(temp, FieldAddress(instance_reg, field().Offset()));
     }
-    __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+    switch (cid) {
+      case kDoubleCid:
+        __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+      break;
+      default:
+        UNREACHABLE();
+    }
     return;
   }
 
@@ -1755,22 +1771,33 @@
     Register temp2 = locs()->temp(1).reg();
     DRegister fpu_temp = locs()->temp(2).fpu_reg();
 
-    Label store_pointer, copy_payload;
+    Label store_pointer;
+    Label copy_double;
+    Label store_double;
+
     __ LoadObject(temp, Field::ZoneHandle(field().raw()));
-    __ lw(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
-    __ BranchNotEqual(temp2, kDoubleCid, &store_pointer);
+
     __ lw(temp2, FieldAddress(temp, Field::is_nullable_offset()));
     __ BranchEqual(temp2, kNullCid, &store_pointer);
+
     __ lbu(temp2, FieldAddress(temp, Field::kind_bits_offset()));
     __ andi(CMPRES1, temp2, Immediate(1 << Field::kUnboxingCandidateBit));
     __ beq(CMPRES1, ZR, &store_pointer);
 
+    __ lw(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
+    __ BranchEqual(temp2, kDoubleCid, &store_double);
+
+    // Fall through.
+    __ b(&store_pointer);
+
+    __ Bind(&store_double);
+
     __ lw(temp, FieldAddress(instance_reg, field().Offset()));
     __ BranchNotEqual(temp, reinterpret_cast<int32_t>(Object::null()),
-                      &copy_payload);
+                      &copy_double);
 
     StoreInstanceFieldSlowPath* slow_path =
-        new StoreInstanceFieldSlowPath(this);
+        new StoreInstanceFieldSlowPath(this, compiler->double_class());
     compiler->AddSlowPathCode(slow_path);
 
     if (!compiler->is_optimizing()) {
@@ -1788,7 +1815,7 @@
                        FieldAddress(instance_reg, field().Offset()),
                        temp2);
 
-    __ Bind(&copy_payload);
+    __ Bind(&copy_double);
     __ LoadDFromOffset(fpu_temp,
                        value_reg,
                        Double::value_offset() - kHeapObjectTag);
@@ -1897,11 +1924,12 @@
 
 
 LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
-  const intptr_t kNumInputs = 1;
+  const intptr_t kNumInputs = 2;
   const intptr_t kNumTemps = 0;
   LocationSummary* locs =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
   locs->set_in(0, Location::RegisterLocation(A0));
+  locs->set_in(1, Location::RegisterLocation(A1));
   locs->set_out(Location::RegisterLocation(V0));
   return locs;
 }
@@ -1911,7 +1939,7 @@
   __ TraceSimMsg("CreateArrayInstr");
   // Allocate the array.  A1 = length, A0 = element type.
   ASSERT(locs()->in(0).reg() == A0);
-  __ LoadImmediate(A1, Smi::RawValue(num_elements()));
+  ASSERT(locs()->in(1).reg() == A1);
   compiler->GenerateCall(token_pos(),
                          &StubCode::AllocateArrayLabel(),
                          PcDescriptors::kOther,
@@ -2003,7 +2031,15 @@
     DRegister result = locs()->out().fpu_reg();
     Register temp = locs()->temp(0).reg();
     __ lw(temp, FieldAddress(instance_reg, offset_in_bytes()));
-    __ LoadDFromOffset(result, temp, Double::value_offset() - kHeapObjectTag);
+    intptr_t cid = field()->UnboxedFieldCid();
+    switch (cid) {
+      case kDoubleCid:
+        __ LoadDFromOffset(result, temp,
+                           Double::value_offset() - kHeapObjectTag);
+        break;
+      default:
+        UNREACHABLE();
+    }
     return;
   }
 
@@ -2014,18 +2050,25 @@
     DRegister value = locs()->temp(0).fpu_reg();
 
     Label load_pointer;
+    Label load_double;
+
     __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
 
     FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
     FieldAddress field_nullability_operand(result_reg,
                                            Field::is_nullable_offset());
 
-    __ lw(temp, field_cid_operand);
-    __ BranchNotEqual(temp, kDoubleCid, &load_pointer);
-
     __ lw(temp, field_nullability_operand);
     __ BranchEqual(temp, kNullCid, &load_pointer);
 
+    __ lw(temp, field_cid_operand);
+    __ BranchEqual(temp, kDoubleCid, &load_double);
+
+    // Fall through.
+    __ b(&load_pointer);
+
+    __ Bind(&load_double);
+
     BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
     compiler->AddSlowPathCode(slow_path);
 
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index bc1a553..f47abad 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -1492,16 +1492,16 @@
 
 class StoreInstanceFieldSlowPath : public SlowPathCode {
  public:
-  explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
-      : instruction_(instruction) { }
+  StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction,
+                             const Class& cls)
+      : instruction_(instruction), cls_(cls) { }
 
   virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
     __ Comment("StoreInstanceFieldSlowPath");
     __ Bind(entry_label());
-    const Class& double_class = compiler->double_class();
     const Code& stub =
-        Code::Handle(StubCode::GetAllocationStubForClass(double_class));
-    const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+        Code::Handle(StubCode::GetAllocationStubForClass(cls_));
+    const ExternalLabel label(cls_.ToCString(), stub.EntryPoint());
 
     LocationSummary* locs = instruction_->locs();
     locs->live_registers()->Remove(locs->out());
@@ -1519,6 +1519,7 @@
 
  private:
   StoreInstanceFieldInstr* instruction_;
+  const Class& cls_;
 };
 
 
@@ -1562,13 +1563,23 @@
     XmmRegister value = locs()->in(1).fpu_reg();
     Register temp = locs()->temp(0).reg();
     Register temp2 = locs()->temp(1).reg();
+    const intptr_t cid = field().UnboxedFieldCid();
 
     if (is_initialization_) {
+      const Class* cls = NULL;
+      switch (cid) {
+        case kDoubleCid:
+          cls = &compiler->double_class();
+          break;
+        // TODO(johnmccutchan): Add kFloat32x4Cid here.
+        default:
+          UNREACHABLE();
+      }
       StoreInstanceFieldSlowPath* slow_path =
-          new StoreInstanceFieldSlowPath(this);
+          new StoreInstanceFieldSlowPath(this, *cls);
       compiler->AddSlowPathCode(slow_path);
 
-      __ TryAllocate(compiler->double_class(),
+      __ TryAllocate(*cls,
                      slow_path->entry_label(),
                      Assembler::kFarJump,
                      temp,
@@ -1581,7 +1592,14 @@
     } else {
       __ movq(temp, FieldAddress(instance_reg, field().Offset()));
     }
-    __ movsd(FieldAddress(temp, Double::value_offset()), value);
+    switch (cid) {
+      case kDoubleCid:
+      __ movsd(FieldAddress(temp, Double::value_offset()), value);
+      // TODO(johnmccutchan): Add kFloat32x4Cid here.
+      break;
+      default:
+        UNREACHABLE();
+    }
     return;
   }
 
@@ -1591,24 +1609,35 @@
     Register temp2 = locs()->temp(1).reg();
     FpuRegister fpu_temp = locs()->temp(2).fpu_reg();
 
-    Label store_pointer, copy_payload;
+    Label store_pointer;
+    Label copy_double;
+    Label store_double;
+
     __ LoadObject(temp, Field::ZoneHandle(field().raw()), PP);
-    __ cmpq(FieldAddress(temp, Field::guarded_cid_offset()),
-            Immediate(kDoubleCid));
-    __ j(NOT_EQUAL, &store_pointer);
+
     __ cmpq(FieldAddress(temp, Field::is_nullable_offset()),
             Immediate(kNullCid));
     __ j(EQUAL, &store_pointer);
+
     __ movzxb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
     __ testq(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
     __ j(ZERO, &store_pointer);
 
+    __ cmpq(FieldAddress(temp, Field::guarded_cid_offset()),
+            Immediate(kDoubleCid));
+    __ j(EQUAL, &store_double);
+
+    // Fall through.
+    __ jmp(&store_pointer);
+
+    __ Bind(&store_double);
+
     __ movq(temp, FieldAddress(instance_reg, field().Offset()));
     __ CompareObject(temp, Object::null_object(), PP);
-    __ j(NOT_EQUAL, &copy_payload);
+    __ j(NOT_EQUAL, &copy_double);
 
     StoreInstanceFieldSlowPath* slow_path =
-        new StoreInstanceFieldSlowPath(this);
+        new StoreInstanceFieldSlowPath(this, compiler->double_class());
     compiler->AddSlowPathCode(slow_path);
 
     if (!compiler->is_optimizing()) {
@@ -1626,7 +1655,7 @@
                        FieldAddress(instance_reg, field().Offset()),
                        temp2);
 
-    __ Bind(&copy_payload);
+    __ Bind(&copy_double);
     __ movsd(fpu_temp, FieldAddress(value_reg, Double::value_offset()));
     __ movsd(FieldAddress(temp, Double::value_offset()), fpu_temp);
     __ jmp(&skip_store);
@@ -1728,11 +1757,12 @@
 
 
 LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
-  const intptr_t kNumInputs = 1;
+  const intptr_t kNumInputs = 2;
   const intptr_t kNumTemps = 0;
   LocationSummary* locs =
       new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
   locs->set_in(0, Location::RegisterLocation(RBX));
+  locs->set_in(1, Location::RegisterLocation(R10));
   locs->set_out(Location::RegisterLocation(RAX));
   return locs;
 }
@@ -1741,7 +1771,7 @@
 void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   // Allocate the array.  R10 = length, RBX = element type.
   ASSERT(locs()->in(0).reg() == RBX);
-  __ LoadImmediate(R10, Immediate(Smi::RawValue(num_elements())), PP);
+  ASSERT(locs()->in(1).reg() == R10);
   compiler->GenerateCall(token_pos(),
                          &StubCode::AllocateArrayLabel(),
                          PcDescriptors::kOther,
@@ -1831,7 +1861,15 @@
     XmmRegister result = locs()->out().fpu_reg();
     Register temp = locs()->temp(0).reg();
     __ movq(temp, FieldAddress(instance_reg, offset_in_bytes()));
-    __ movsd(result, FieldAddress(temp, Double::value_offset()));
+    intptr_t cid = field()->UnboxedFieldCid();
+    switch (cid) {
+      case kDoubleCid:
+        __ movsd(result, FieldAddress(temp, Double::value_offset()));
+        break;
+      // TODO(johnmccutchan): Add Float32x4 path here.
+      default:
+        UNREACHABLE();
+    }
     return;
   }
 
@@ -1842,16 +1880,23 @@
     XmmRegister value = locs()->temp(0).fpu_reg();
 
     Label load_pointer;
+    Label load_double;
+
     __ LoadObject(result, Field::ZoneHandle(field()->raw()), PP);
 
-
-    __ cmpq(FieldAddress(result, Field::guarded_cid_offset()),
-            Immediate(kDoubleCid));
-    __ j(NOT_EQUAL, &load_pointer);
     __ cmpq(FieldAddress(result, Field::is_nullable_offset()),
             Immediate(kNullCid));
     __ j(EQUAL, &load_pointer);
 
+    __ cmpq(FieldAddress(result, Field::guarded_cid_offset()),
+            Immediate(kDoubleCid));
+    __ j(EQUAL, &load_double);
+
+    // Fall through.
+    __ jmp(&load_pointer);
+
+    __ Bind(&load_double);
+
     BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
     compiler->AddSlowPathCode(slow_path);
 
@@ -1869,6 +1914,9 @@
     __ movsd(value, FieldAddress(temp, Double::value_offset()));
     __ movsd(FieldAddress(result, Double::value_offset()), value);
     __ jmp(&done);
+
+    // TODO(johnmccutchan): Add Float32x4 path here.
+
     __ Bind(&load_pointer);
   }
   __ movq(result, FieldAddress(instance_reg, offset_in_bytes()));
diff --git a/runtime/vm/intrinsifier.h b/runtime/vm/intrinsifier.h
index d1605d9..82f4d11 100644
--- a/runtime/vm/intrinsifier.h
+++ b/runtime/vm/intrinsifier.h
@@ -117,6 +117,7 @@
   V(_Float64Array, _new, TypedData_Float64Array_new, 311965335)                \
   V(_Float32x4Array, _new, TypedData_Float32x4Array_new, 775330800)            \
   V(_Int32x4Array, _new, TypedData_Int32x4Array_new, 2074077580)               \
+  V(_Float64x2Array, _new, TypedData_Float64x2Array_new, 1540328543)           \
   V(_Int8Array, ., TypedData_Int8Array_factory, 545976988)                     \
   V(_Uint8Array, ., TypedData_Uint8Array_factory, 981297074)                   \
   V(_Uint8ClampedArray, ., TypedData_Uint8ClampedArray_factory, 1617830104)    \
@@ -130,6 +131,7 @@
   V(_Float64Array, ., TypedData_Float64Array_factory, 1599078532)              \
   V(_Float32x4Array, ., TypedData_Float32x4Array_factory, 879975401)           \
   V(_Int32x4Array, ., TypedData_Int32x4Array_factory, 924582681)               \
+  V(_Float64x2Array, ., TypedData_Float64x2Array_factory, 1654170890)          \
 
 
 // TODO(srdjan): Implement _FixedSizeArrayIterator, get:current and
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 10a1578..abe9dda 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -312,6 +312,7 @@
       stacktrace_(NULL),
       stack_frame_index_(-1),
       object_histogram_(NULL),
+      cha_used_(false),
       object_id_ring_(NULL),
       profiler_data_(NULL),
       REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index ff1682c..8356d97 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -113,6 +113,9 @@
 
   ObjectHistogram* object_histogram() { return object_histogram_; }
 
+  bool cha_used() const { return cha_used_; }
+  void set_cha_used(bool value) { cha_used_ = value; }
+
   MegamorphicCacheTable* megamorphic_cache_table() {
     return &megamorphic_cache_table_;
   }
@@ -457,6 +460,8 @@
   intptr_t stack_frame_index_;
   ObjectHistogram* object_histogram_;
 
+  bool cha_used_;
+
   // Ring buffer of objects assigned an id.
   ObjectIdRing* object_id_ring_;
 
diff --git a/runtime/vm/mirrors_api_impl.cc b/runtime/vm/mirrors_api_impl.cc
index ce15960..a608ea9 100644
--- a/runtime/vm/mirrors_api_impl.cc
+++ b/runtime/vm/mirrors_api_impl.cc
@@ -42,7 +42,12 @@
   if (obj.IsType() || obj.IsClass()) {
     const Class& cls = (obj.IsType()) ?
         Class::Handle(Type::Cast(obj).type_class()) : Class::Cast(obj);
-    return Dart_NewStringFromCString(cls.ToCString());
+    const char* str = cls.ToCString();
+    if (str == NULL) {
+      RETURN_NULL_ERROR(str);
+    }
+    CHECK_CALLBACK_STATE(isolate);
+    return Api::NewHandle(isolate, String::New(str));
   } else {
     RETURN_TYPE_ERROR(isolate, object, Class/Type);
   }
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c5c9a41..1de1ac0 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -59,6 +59,8 @@
 DEFINE_FLAG(bool, throw_on_javascript_int_overflow, false,
     "Throw an exception when the result of an integer calculation will not "
     "fit into a javascript integer.");
+DEFINE_FLAG(bool, use_lib_cache, true, "Use library name cache");
+
 DECLARE_FLAG(bool, eliminate_type_checks);
 DECLARE_FLAG(bool, enable_type_checks);
 DECLARE_FLAG(bool, error_on_bad_override);
@@ -1189,6 +1191,9 @@
   cls = Class::New<Int32x4>();
   object_store->set_int32x4_class(cls);
   RegisterPrivateClass(cls, Symbols::_Int32x4(), lib);
+  cls = Class::New<Float64x2>();
+  object_store->set_float64x2_class(cls);
+  RegisterPrivateClass(cls, Symbols::_Float64x2(), lib);
 
   cls = Class::New<Instance>(kIllegalCid);
   RegisterClass(cls, Symbols::Float32x4(), lib);
@@ -1208,6 +1213,15 @@
   type = Type::NewNonParameterizedType(cls);
   object_store->set_int32x4_type(type);
 
+  cls = Class::New<Instance>(kIllegalCid);
+  RegisterClass(cls, Symbols::Float64x2(), lib);
+  cls.set_num_type_arguments(0);
+  cls.set_num_own_type_arguments(0);
+  cls.set_is_prefinalized();
+  pending_classes.Add(cls);
+  type = Type::NewNonParameterizedType(cls);
+  object_store->set_float64x2_type(type);
+
   object_store->set_typed_data_classes(typed_data_classes);
 
   // Set the super type of class Stacktrace to Object type so that the
@@ -1348,6 +1362,9 @@
   cls = Class::New<Int32x4>();
   object_store->set_int32x4_class(cls);
 
+  cls = Class::New<Float64x2>();
+  object_store->set_float64x2_class(cls);
+
 #define REGISTER_TYPED_DATA_CLASS(clazz)                                       \
   cls = Class::NewTypedDataClass(kTypedData##clazz##Cid);
   CLASS_LIST_TYPED_DATA(REGISTER_TYPED_DATA_CLASS);
@@ -2319,6 +2336,157 @@
 }
 
 
+// Helper class to handle an array of code weak properties. Implements
+// registration and disabling of stored code objects.
+class WeakCodeReferences : public ValueObject {
+ public:
+  explicit WeakCodeReferences(const Array& value) : array_(value) {}
+  virtual ~WeakCodeReferences() {}
+
+  void Register(const Code& value) {
+    if (!array_.IsNull()) {
+      // Try to find and reuse cleared WeakProperty to avoid allocating new one.
+      WeakProperty& weak_property = WeakProperty::Handle();
+      for (intptr_t i = 0; i < array_.Length(); i++) {
+        weak_property ^= array_.At(i);
+        if (weak_property.key() == Code::null()) {
+          // Empty property found. Reuse it.
+          weak_property.set_key(value);
+          return;
+        }
+      }
+    }
+
+    const WeakProperty& weak_property = WeakProperty::Handle(
+        WeakProperty::New(Heap::kOld));
+    weak_property.set_key(value);
+
+    intptr_t length = array_.IsNull() ? 0 : array_.Length();
+    const Array& new_array = Array::Handle(
+        Array::Grow(array_, length + 1, Heap::kOld));
+    new_array.SetAt(length, weak_property);
+    UpdateArrayTo(new_array);
+  }
+
+  virtual void UpdateArrayTo(const Array& array) = 0;
+  virtual void ReportDeoptimization(const Code& code) = 0;
+  virtual void ReportSwitchingCode(const Code& code) = 0;
+
+  static bool IsOptimizedCode(const Array& dependent_code, const Code& code) {
+    if (!code.is_optimized()) {
+      return false;
+    }
+    WeakProperty& weak_property = WeakProperty::Handle();
+    for (intptr_t i = 0; i < dependent_code.Length(); i++) {
+      weak_property ^= dependent_code.At(i);
+      if (code.raw() == weak_property.key()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  void DisableCode() {
+    const Array& code_objects = Array::Handle(array_.raw());
+    if (code_objects.IsNull()) {
+      return;
+    }
+    UpdateArrayTo(Object::null_array());
+    // Disable all code on stack.
+    Code& code = Code::Handle();
+    {
+      DartFrameIterator iterator;
+      StackFrame* frame = iterator.NextFrame();
+      while (frame != NULL) {
+        code = frame->LookupDartCode();
+        if (IsOptimizedCode(code_objects, code)) {
+          ReportDeoptimization(code);
+          DeoptimizeAt(code, frame->pc());
+        }
+        frame = iterator.NextFrame();
+      }
+    }
+
+    // Switch functions that use dependent code to unoptimized code.
+    WeakProperty& weak_property = WeakProperty::Handle();
+    Function& function = Function::Handle();
+    for (intptr_t i = 0; i < code_objects.Length(); i++) {
+      weak_property ^= code_objects.At(i);
+      code ^= weak_property.key();
+      if (code.IsNull()) {
+        // Code was garbage collected already.
+        continue;
+      }
+
+      function ^= code.function();
+      // If function uses dependent code switch it to unoptimized.
+      if (function.CurrentCode() == code.raw()) {
+        ASSERT(function.HasOptimizedCode());
+        ReportSwitchingCode(code);
+        function.SwitchToUnoptimizedCode();
+      }
+    }
+  }
+
+ private:
+  const Array& array_;
+  DISALLOW_COPY_AND_ASSIGN(WeakCodeReferences);
+};
+
+
+class CHACodeArray : public WeakCodeReferences {
+ public:
+  explicit CHACodeArray(const Class& cls)
+      : WeakCodeReferences(Array::Handle(cls.cha_codes())), cls_(cls) {
+  }
+
+  virtual void UpdateArrayTo(const Array& value) {
+    cls_.set_cha_codes(value);
+  }
+
+  virtual void ReportDeoptimization(const Code& code) {
+    if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+      Function& function = Function::Handle(code.function());
+      OS::PrintErr("Deoptimizing %s because CHA optimized (%s).\n",
+          function.ToFullyQualifiedCString(),
+          cls_.ToCString());
+    }
+  }
+
+  virtual void ReportSwitchingCode(const Code& code) {
+    if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+      Function& function = Function::Handle(code.function());
+      OS::PrintErr("Switching %s to unoptimized code because CHA invalid"
+                   " (%s)\n",
+                   function.ToFullyQualifiedCString(),
+                   cls_.ToCString());
+    }
+  }
+
+ private:
+  const Class& cls_;
+  DISALLOW_COPY_AND_ASSIGN(CHACodeArray);
+};
+
+
+void Class::RegisterCHACode(const Code& code) {
+  ASSERT(code.is_optimized());
+  CHACodeArray a(*this);
+  a.Register(code);
+}
+
+
+void Class::DisableCHAOptimizedCode() {
+  CHACodeArray a(*this);
+  a.DisableCode();
+}
+
+
+void Class::set_cha_codes(const Array& cache) const {
+  StorePointer(&raw_ptr()->cha_codes_, cache.raw());
+}
+
+
 // Apply the members from the patch class to the original class.
 bool Class::ApplyPatch(const Class& patch, Error* error) const {
   ASSERT(error != NULL);
@@ -2948,6 +3116,11 @@
 }
 
 
+void Class::set_is_fields_marked_nullable() const {
+  set_state_bits(FieldsMarkedNullableBit::update(true, raw_ptr()->state_bits_));
+}
+
+
 void Class::set_is_finalized() const {
   ASSERT(!is_finalized());
   set_state_bits(ClassFinalizedBits::update(RawClass::kFinalized,
@@ -6118,6 +6291,7 @@
 
 
 RawString* Field::GetterName(const String& field_name) {
+  CompilerStats::make_accessor_name++;
   return String::Concat(Symbols::GetterPrefix(), field_name);
 }
 
@@ -6129,6 +6303,7 @@
 
 
 RawString* Field::SetterName(const String& field_name) {
+  CompilerStats::make_accessor_name++;
   return String::Concat(Symbols::SetterPrefix(), field_name);
 }
 
@@ -6140,11 +6315,13 @@
 
 
 RawString* Field::NameFromGetter(const String& getter_name) {
+  CompilerStats::make_field_name++;
   return String::SubString(getter_name, strlen(kGetterPrefix));
 }
 
 
 RawString* Field::NameFromSetter(const String& setter_name) {
+  CompilerStats::make_field_name++;
   return String::SubString(setter_name, strlen(kSetterPrefix));
 }
 
@@ -6278,6 +6455,19 @@
 }
 
 
+bool Field::IsUnboxedField() const {
+  // TODO(johnmccutchan): Add kFloat32x4Cid here.
+  return is_unboxing_candidate() && !is_final() && !is_nullable() &&
+         ((guarded_cid() == kDoubleCid));
+}
+
+
+bool Field::IsPotentialUnboxedField() const {
+  return is_unboxing_candidate() &&
+         (IsUnboxedField() || (!is_final() && (guarded_cid() == kIllegalCid)));
+}
+
+
 const char* Field::ToCString() const {
   if (IsNull()) {
     return "Field::null";
@@ -6360,107 +6550,55 @@
 
 
 void Field::set_dependent_code(const Array& array) const {
-  raw_ptr()->dependent_code_ = array.raw();
+  StorePointer(&raw_ptr()->dependent_code_, array.raw());
 }
 
 
+class FieldDependentArray : public WeakCodeReferences {
+ public:
+  explicit FieldDependentArray(const Field& field)
+      : WeakCodeReferences(Array::Handle(field.dependent_code())),
+                           field_(field) {}
+
+  virtual void UpdateArrayTo(const Array& value) {
+    field_.set_dependent_code(value);
+  }
+
+  virtual void ReportDeoptimization(const Code& code) {
+    if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+      Function& function = Function::Handle(code.function());
+          OS::PrintErr("Deoptimizing %s because guard on field %s failed.\n",
+          function.ToFullyQualifiedCString(),
+          field_.ToCString());
+    }
+  }
+
+  virtual void ReportSwitchingCode(const Code& code) {
+    if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
+      Function& function = Function::Handle(code.function());
+      OS::PrintErr("Switching %s to unoptimized code because guard"
+                   " on field %s was violated.\n",
+                   function.ToFullyQualifiedCString(),
+                   field_.ToCString());
+    }
+  }
+
+ private:
+  const Field& field_;
+  DISALLOW_COPY_AND_ASSIGN(FieldDependentArray);
+};
+
+
 void Field::RegisterDependentCode(const Code& code) const {
-  const Array& dependent = Array::Handle(dependent_code());
-
-  if (!dependent.IsNull()) {
-    // Try to find and reuse cleared WeakProperty to avoid allocating new one.
-    WeakProperty& weak_property = WeakProperty::Handle();
-    for (intptr_t i = 0; i < dependent.Length(); i++) {
-      weak_property ^= dependent.At(i);
-      if (weak_property.key() == Code::null()) {
-        // Empty property found. Reuse it.
-        weak_property.set_key(code);
-        return;
-      }
-    }
-  }
-
-  const WeakProperty& weak_property = WeakProperty::Handle(
-      WeakProperty::New(Heap::kOld));
-  weak_property.set_key(code);
-
-  intptr_t length = dependent.IsNull() ? 0 : dependent.Length();
-  const Array& new_dependent = Array::Handle(
-      Array::Grow(dependent, length + 1, Heap::kOld));
-  new_dependent.SetAt(length, weak_property);
-  set_dependent_code(new_dependent);
-}
-
-
-static bool IsDependentCode(const Array& dependent_code, const Code& code) {
-  if (!code.is_optimized()) {
-    return false;
-  }
-
-  WeakProperty& weak_property = WeakProperty::Handle();
-  for (intptr_t i = 0; i < dependent_code.Length(); i++) {
-    weak_property ^= dependent_code.At(i);
-    if (code.raw() == weak_property.key()) {
-      return true;
-    }
-  }
-
-  return false;
+  ASSERT(code.is_optimized());
+  FieldDependentArray a(*this);
+  a.Register(code);
 }
 
 
 void Field::DeoptimizeDependentCode() const {
-  const Array& code_objects = Array::Handle(dependent_code());
-
-  if (code_objects.IsNull()) {
-    return;
-  }
-  set_dependent_code(Object::null_array());
-
-  // Deoptimize all dependent code on the stack.
-  Code& code = Code::Handle();
-  {
-    DartFrameIterator iterator;
-    StackFrame* frame = iterator.NextFrame();
-    while (frame != NULL) {
-      code = frame->LookupDartCode();
-      if (IsDependentCode(code_objects, code)) {
-        if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
-          Function& function = Function::Handle(code.function());
-          OS::PrintErr("Deoptimizing %s because guard on field %s failed.\n",
-              function.ToFullyQualifiedCString(),
-              ToCString());
-        }
-        DeoptimizeAt(code, frame->pc());
-      }
-      frame = iterator.NextFrame();
-    }
-  }
-
-  // Switch functions that use dependent code to unoptimized code.
-  WeakProperty& weak_property = WeakProperty::Handle();
-  Function& function = Function::Handle();
-  for (intptr_t i = 0; i < code_objects.Length(); i++) {
-    weak_property ^= code_objects.At(i);
-    code ^= weak_property.key();
-    if (code.IsNull()) {
-      // Code was garbage collected already.
-      continue;
-    }
-
-    function ^= code.function();
-    // If function uses dependent code switch it to unoptimized.
-    if (function.CurrentCode() == code.raw()) {
-      ASSERT(function.HasOptimizedCode());
-      if (FLAG_trace_deoptimization || FLAG_trace_deoptimization_verbose) {
-        OS::PrintErr("Switching %s to unoptimized code because guard"
-                     " on field %s was violated.\n",
-                     function.ToFullyQualifiedCString(),
-                     ToCString());
-      }
-      function.SwitchToUnoptimizedCode();
-    }
-  }
+  FieldDependentArray a(*this);
+  a.DisableCode();
 }
 
 
@@ -7405,39 +7543,37 @@
   intptr_t length = src.Length();
   intptr_t line = 1 + line_offset();
   intptr_t column = 1;
-  intptr_t lookahead = 0;
+  intptr_t scan_position = 0;
   intptr_t snippet_start = -1;
   intptr_t snippet_end = -1;
   if (from_line - line_offset() == 1) {
     column += col_offset();
   }
-  char c = src.CharAt(lookahead);
-  while (lookahead != length) {
-    if (snippet_start == -1) {
-      if ((line == from_line) && (column == from_column)) {
-        snippet_start = lookahead;
-      }
-    } else if ((line == to_line) && (column == to_column)) {
-      snippet_end = lookahead;
-      break;
-    }
+
+  while (scan_position != length) {
+    char c = src.CharAt(scan_position);
     if (c == '\n') {
       line++;
       column = 0;
-    }
-    column++;
-    lookahead++;
-    if (lookahead != length) {
-      // Replace '\r' with '\n' and a sequence of '\r' '\n' with a single '\n'.
-      if (src.CharAt(lookahead) == '\r') {
-        c = '\n';
-        if (lookahead + 1 != length && src.CharAt(lookahead) == '\n') {
-          lookahead++;
-        }
-      } else {
-        c = src.CharAt(lookahead);
+    } else if (c == '\r') {
+      line++;
+      column = 0;
+      if ((scan_position + 1 != length) &&
+          (src.CharAt(scan_position + 1) == '\n')) {
+        scan_position++;
       }
     }
+    scan_position++;
+    column++;
+
+    if (snippet_start == -1) {
+      if ((line == from_line) && (column == from_column)) {
+        snippet_start = scan_position;
+      }
+    } else if ((line == to_line) && (column == to_column)) {
+      snippet_end = scan_position;
+      break;
+    }
   }
   String& snippet = String::Handle();
   if ((snippet_start != -1) && (snippet_end != -1)) {
@@ -7756,6 +7892,136 @@
 }
 
 
+RawObject* Library::ResolveName(const String& name) const {
+  Object& obj = Object::Handle();
+  if (FLAG_use_lib_cache && LookupResolvedNamesCache(name, &obj)) {
+    return obj.raw();
+  }
+  obj = LookupLocalObject(name);
+  if (!obj.IsNull()) {
+    // Names that are in this library's dictionary and are unmangled
+    // are not cached. This reduces the size of the the cache.
+    return obj.raw();
+  }
+  String& accessor_name = String::Handle(Field::GetterName(name));
+  obj = LookupLocalObject(accessor_name);
+  if (obj.IsNull()) {
+    accessor_name = Field::SetterName(name);
+    obj = LookupLocalObject(accessor_name);
+    if (obj.IsNull()) {
+      obj = LookupImportedObject(name);
+    }
+  }
+  AddToResolvedNamesCache(name, obj);
+  return obj.raw();
+}
+
+
+static intptr_t ResolvedNameCacheSize(const Array& cache) {
+  return (cache.Length() - 1) / 2;
+}
+
+
+// Returns true if the name is found in the cache, false no cache hit.
+// obj is set to the cached entry. It may be null, indicating that the
+// name does not resolve to anything in this library.
+bool Library::LookupResolvedNamesCache(const String& name,
+                                       Object* obj) const {
+  const Array& cache = Array::Handle(resolved_names());
+  const intptr_t cache_size = ResolvedNameCacheSize(cache);
+  intptr_t index = name.Hash() % cache_size;
+  String& entry_name = String::Handle();
+  entry_name ^= cache.At(index);
+  while (!entry_name.IsNull()) {
+    if (entry_name.Equals(name)) {
+      CompilerStats::num_lib_cache_hit++;
+      *obj = cache.At(index + cache_size);
+      return true;
+    }
+    index = (index + 1) % cache_size;
+    entry_name ^= cache.At(index);
+  }
+  *obj = Object::null();
+  return false;
+}
+
+
+void Library::GrowResolvedNamesCache() const {
+  const Array& old_cache = Array::Handle(resolved_names());
+  const intptr_t old_cache_size = ResolvedNameCacheSize(old_cache);
+
+  // Create empty new cache and add entries from the old cache.
+  const intptr_t new_cache_size = old_cache_size * 3 / 2;
+  InitResolvedNamesCache(new_cache_size);
+  String& name = String::Handle();
+  Object& entry = Object::Handle();
+  for (intptr_t i = 0; i < old_cache_size; i++) {
+    name ^= old_cache.At(i);
+    if (!name.IsNull()) {
+      entry = old_cache.At(i + old_cache_size);
+      AddToResolvedNamesCache(name, entry);
+    }
+  }
+}
+
+
+// Add a name to the resolved name cache. This name resolves to the
+// given object in this library scope. obj may be null, which means
+// the name does not resolve to anything in this library scope.
+void Library::AddToResolvedNamesCache(const String& name,
+                                      const Object& obj) const {
+  if (!FLAG_use_lib_cache) {
+    return;
+  }
+  const Array& cache = Array::Handle(resolved_names());
+  // let N = cache.Length();
+  // The entry cache[N-1] is used as a counter
+  // The array entries [0..N-2] are used as cache entries.
+  //   cache[i] contains the name of the entry
+  //   cache[i+(N-1)/2] contains the resolved entity, or NULL if that name
+  //   is not present in the library.
+  const intptr_t counter_index = cache.Length() - 1;
+  intptr_t cache_size = ResolvedNameCacheSize(cache);
+  intptr_t index = name.Hash() % cache_size;
+  String& entry_name = String::Handle();
+  entry_name ^= cache.At(index);
+  // An empty spot will be found because we keep the hash set at most 75% full.
+  while (!entry_name.IsNull()) {
+    index = (index + 1) % cache_size;
+    entry_name ^= cache.At(index);
+  }
+  // Insert the object at the empty slot.
+  cache.SetAt(index, name);
+  ASSERT(cache.At(index + cache_size) == Object::null());
+  cache.SetAt(index + cache_size, obj);
+
+  // One more element added.
+  intptr_t num_used = Smi::Value(Smi::RawCast(cache.At(counter_index))) + 1;
+  cache.SetAt(counter_index, Smi::Handle(Smi::New(num_used)));
+  CompilerStats::num_names_cached++;
+
+  // Rehash if symbol_table is 75% full.
+  if (num_used > ((cache_size / 4) * 3)) {
+    CompilerStats::num_names_cached -= num_used;
+    GrowResolvedNamesCache();
+  }
+}
+
+
+void Library::InvalidateResolvedName(const String& name) const {
+  Object& entry = Object::Handle();
+  if (LookupResolvedNamesCache(name, &entry)) {
+    InvalidateResolvedNamesCache();
+  }
+}
+
+
+void Library::InvalidateResolvedNamesCache() const {
+  const intptr_t kInvalidatedCacheSize = 16;
+  InitResolvedNamesCache(kInvalidatedCacheSize);
+}
+
+
 void Library::GrowDictionary(const Array& dict, intptr_t dict_size) const {
   // TODO(iposva): Avoid exponential growth.
   intptr_t new_dict_size = dict_size * 2;
@@ -7888,9 +8154,11 @@
 
 
 void Library::AddClass(const Class& cls) const {
-  AddObject(cls, String::Handle(cls.Name()));
+  const String& class_name = String::Handle(cls.Name());
+  AddObject(cls, class_name);
   // Link class to this library.
   cls.set_library(*this);
+  InvalidateResolvedName(class_name);
 }
 
 static void AddScriptIfUnique(const GrowableObjectArray& scripts,
@@ -8072,17 +8340,6 @@
 }
 
 
-RawObject* Library::LookupObject(const String& name) const {
-  // First check if name is found in the local scope of the library.
-  Object& obj = Object::Handle(LookupLocalObject(name));
-  if (!obj.IsNull()) {
-    return obj.raw();
-  }
-  // Now check if name is found in any imported libs.
-  return LookupImportedObject(name);
-}
-
-
 RawObject* Library::LookupImportedObject(const String& name) const {
   Object& obj = Object::Handle();
   Namespace& import = Namespace::Handle();
@@ -8121,7 +8378,7 @@
 
 
 RawClass* Library::LookupClass(const String& name) const {
-  Object& obj = Object::Handle(LookupObject(name));
+  Object& obj = Object::Handle(ResolveName(name));
   if (obj.IsClass()) {
     return Class::Cast(obj).raw();
   }
@@ -8260,15 +8517,24 @@
 }
 
 
-void Library::InitClassDictionary() const {
+static RawArray* NewDictionary(intptr_t initial_size) {
+  const Array& dict = Array::Handle(Array::New(initial_size + 1, Heap::kOld));
   // The last element of the dictionary specifies the number of in use slots.
+  dict.SetAt(initial_size, Smi::Handle(Smi::New(0)));
+  return dict.raw();
+}
+
+
+void Library::InitResolvedNamesCache(intptr_t size) const {
+  // Need space for 'size' names and 'size' resolved object entries.
+  StorePointer(&raw_ptr()->resolved_names_, NewDictionary(2 * size));
+}
+
+
+void Library::InitClassDictionary() const {
   // TODO(iposva): Find reasonable initial size.
   const int kInitialElementCount = 16;
-
-  const Array& dictionary =
-      Array::Handle(Array::New(kInitialElementCount + 1, Heap::kOld));
-  dictionary.SetAt(kInitialElementCount, Smi::Handle(Smi::New(0)));
-  StorePointer(&raw_ptr()->dictionary_, dictionary.raw());
+  StorePointer(&raw_ptr()->dictionary_, NewDictionary(kInitialElementCount));
 }
 
 
@@ -8295,6 +8561,7 @@
   result.StorePointer(&result.raw_ptr()->name_, Symbols::Empty().raw());
   result.StorePointer(&result.raw_ptr()->url_, url.raw());
   result.raw_ptr()->private_key_ = Scanner::AllocatePrivateKey(result);
+  result.raw_ptr()->resolved_names_ = Object::empty_array().raw();
   result.raw_ptr()->dictionary_ = Object::empty_array().raw();
   result.StorePointer(&result.raw_ptr()->metadata_,
                       GrowableObjectArray::New(4, Heap::kOld));
@@ -8308,6 +8575,8 @@
   result.set_debuggable(false);
   result.raw_ptr()->load_state_ = RawLibrary::kAllocated;
   result.raw_ptr()->index_ = -1;
+  const intptr_t kInitialNameCacheSize = 64;
+  result.InitResolvedNamesCache(kInitialNameCacheSize);
   result.InitClassDictionary();
   result.InitImportList();
   if (import_core_lib) {
@@ -8382,6 +8651,7 @@
 }
 
 
+// Returns library with given url in current isolate, or NULL.
 RawLibrary* Library::LookupLibrary(const String &url) {
   Isolate* isolate = Isolate::Current();
   Library& lib = Library::Handle(isolate, Library::null());
@@ -10172,8 +10442,11 @@
   jsobj.AddProperty("is_alive", is_alive());
   jsobj.AddProperty("function", Object::Handle(function()));
   JSONArray jsarr(&jsobj, "disassembly");
-  DisassembleToJSONStream formatter(jsarr);
-  Disassemble(&formatter);
+  if (is_alive()) {
+    // Only disassemble alive code objects.
+    DisassembleToJSONStream formatter(jsarr);
+    Disassemble(&formatter);
+  }
 }
 
 
@@ -16366,7 +16639,7 @@
 
 
 RawFloat32x4* Float32x4::New(simd128_value_t value, Heap::Space space) {
-ASSERT(Isolate::Current()->object_store()->float32x4_class() !=
+  ASSERT(Isolate::Current()->object_store()->float32x4_class() !=
          Class::null());
   Float32x4& result = Float32x4::Handle();
   {
@@ -16555,6 +16828,86 @@
 }
 
 
+RawFloat64x2* Float64x2::New(double value0, double value1, Heap::Space space) {
+  ASSERT(Isolate::Current()->object_store()->float64x2_class() !=
+         Class::null());
+  Float64x2& result = Float64x2::Handle();
+  {
+    RawObject* raw = Object::Allocate(Float64x2::kClassId,
+                                      Float64x2::InstanceSize(),
+                                      space);
+    NoGCScope no_gc;
+    result ^= raw;
+  }
+  result.set_x(value0);
+  result.set_y(value1);
+  return result.raw();
+}
+
+
+RawFloat64x2* Float64x2::New(simd128_value_t value, Heap::Space space) {
+  ASSERT(Isolate::Current()->object_store()->float64x2_class() !=
+         Class::null());
+  Float64x2& result = Float64x2::Handle();
+  {
+    RawObject* raw = Object::Allocate(Float64x2::kClassId,
+                                      Float64x2::InstanceSize(),
+                                      space);
+    NoGCScope no_gc;
+    result ^= raw;
+  }
+  result.set_value(value);
+  return result.raw();
+}
+
+
+double Float64x2::x() const {
+  return raw_ptr()->value_[0];
+}
+
+
+double Float64x2::y() const {
+  return raw_ptr()->value_[1];
+}
+
+
+void Float64x2::set_x(double x) const {
+  raw_ptr()->value_[0] = x;
+}
+
+
+void Float64x2::set_y(double y) const {
+  raw_ptr()->value_[1] = y;
+}
+
+
+simd128_value_t Float64x2::value() const {
+  return simd128_value_t().readFrom(&raw_ptr()->value_[0]);
+}
+
+
+void Float64x2::set_value(simd128_value_t value) const {
+  value.writeTo(&raw_ptr()->value_[0]);
+}
+
+
+const char* Float64x2::ToCString() const {
+  const char* kFormat = "[%f, %f]";
+  double _x = x();
+  double _y = y();
+  // Calculate the size of the string.
+  intptr_t len = OS::SNPrint(NULL, 0, kFormat, _x, _y) + 1;
+  char* chars = Isolate::Current()->current_zone()->Alloc<char>(len);
+  OS::SNPrint(chars, len, kFormat, _x, _y);
+  return chars;
+}
+
+
+void Float64x2::PrintToJSONStream(JSONStream* stream, bool ref) const {
+  Instance::PrintToJSONStream(stream, ref);
+}
+
+
 const intptr_t TypedData::element_size[] = {
   1,   // kTypedDataInt8ArrayCid.
   1,   // kTypedDataUint8ArrayCid.
@@ -16569,6 +16922,7 @@
   8,   // kTypedDataFloat64ArrayCid.
   16,  // kTypedDataFloat32x4ArrayCid.
   16,  // kTypedDataInt32x4ArrayCid.
+  16,  // kTypedDataFloat64x2ArrayCid,
 };
 
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 2144156..37dfc34 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -992,6 +992,11 @@
   }
   void set_is_mixin_type_applied() const;
 
+  bool is_fields_marked_nullable() const {
+    return FieldsMarkedNullableBit::decode(raw_ptr()->state_bits_);
+  }
+  void set_is_fields_marked_nullable() const;
+
   uint16_t num_native_fields() const {
     return raw_ptr()->num_native_fields_;
   }
@@ -1069,6 +1074,16 @@
   // otherwise a new object is allocated and returned.
   static RawClass* GetClass(intptr_t class_id, bool is_signature_class);
 
+  // Register code that has used CHA for optimization.
+  // TODO(srdjan): Also register kind of CHA optimization (e.g.: leaf class,
+  // leaf method, ...).
+  void RegisterCHACode(const Code& code);
+
+  void DisableCHAOptimizedCode();
+
+  RawArray* cha_codes() const { return raw_ptr()->cha_codes_; }
+  void set_cha_codes(const Array& value) const;
+
  private:
   enum {
     kAny = 0,
@@ -1089,6 +1104,7 @@
     kMarkedForParsingBit = 8,
     kMixinAppAliasBit = 9,
     kMixinTypeAppliedBit = 10,
+    kFieldsMarkedNullableBit = 11,
   };
   class ConstBit : public BitField<bool, kConstBit, 1> {};
   class ImplementedBit : public BitField<bool, kImplementedBit, 1> {};
@@ -1101,6 +1117,8 @@
   class MarkedForParsingBit : public BitField<bool, kMarkedForParsingBit, 1> {};
   class MixinAppAliasBit : public BitField<bool, kMixinAppAliasBit, 1> {};
   class MixinTypeAppliedBit : public BitField<bool, kMixinTypeAppliedBit, 1> {};
+  class FieldsMarkedNullableBit : public BitField<bool,
+      kFieldsMarkedNullableBit, 1> {};  // NOLINT
 
   void set_name(const String& value) const;
   void set_user_name(const String& value) const;
@@ -2187,17 +2205,14 @@
     return r;
   }
 
-  bool IsUnboxedField() const {
-    return is_unboxing_candidate()
-        && !is_final()
-        && (guarded_cid() == kDoubleCid && !is_nullable());
+  intptr_t UnboxedFieldCid() const {
+    ASSERT(IsUnboxedField());
+    return guarded_cid();
   }
 
-  bool IsPotentialUnboxedField() const {
-    return is_unboxing_candidate()
-        && (IsUnboxedField() ||
-            (!is_final() && (guarded_cid() == kIllegalCid)));
-  }
+  bool IsUnboxedField() const;
+
+  bool IsPotentialUnboxedField() const;
 
   bool is_unboxing_candidate() const {
     return UnboxingCandidateBit::decode(raw_ptr()->kind_bits_);
@@ -2584,7 +2599,6 @@
   void AddObject(const Object& obj, const String& name) const;
   void ReplaceObject(const Object& obj, const String& name) const;
   RawObject* LookupReExport(const String& name) const;
-  RawObject* LookupObject(const String& name) const;
   RawObject* LookupObjectAllowPrivate(const String& name) const;
   RawObject* LookupLocalObjectAllowPrivate(const String& name) const;
   RawObject* LookupLocalObject(const String& name) const;
@@ -2600,6 +2614,15 @@
   RawScript* LookupScript(const String& url) const;
   RawArray* LoadedScripts() const;
 
+  // Resolve name in the scope of this library. First check the cache
+  // of already resolved names for this library. Then look in the
+  // local dictionary for the unmangled name N, the getter name get:N
+  // and setter name set:N.
+  // If the local dictionary contains no entry for these names,
+  // look in the scopes of all libraries that are imported
+  // without a library prefix.
+  RawObject* ResolveName(const String& name) const;
+
   void AddAnonymousClass(const Class& cls) const;
 
   void AddExport(const Namespace& ns) const;
@@ -2708,6 +2731,15 @@
   RawGrowableObjectArray* metadata() const { return raw_ptr()->metadata_; }
   RawArray* dictionary() const { return raw_ptr()->dictionary_; }
   void InitClassDictionary() const;
+
+  RawArray* resolved_names() const { return raw_ptr()->resolved_names_; }
+  void InitResolvedNamesCache(intptr_t size) const;
+  void GrowResolvedNamesCache() const;
+  bool LookupResolvedNamesCache(const String& name, Object* obj) const;
+  void AddToResolvedNamesCache(const String& name, const Object& obj) const;
+  void InvalidateResolvedName(const String& name) const;
+  void InvalidateResolvedNamesCache() const;
+
   void InitImportList() const;
   void GrowDictionary(const Array& dict, intptr_t dict_size) const;
   static RawLibrary* NewLibraryHelper(const String& url,
@@ -5939,6 +5971,36 @@
 };
 
 
+class Float64x2 : public Instance {
+ public:
+  static RawFloat64x2* New(double value0, double value1,
+                           Heap::Space space = Heap::kNew);
+  static RawFloat64x2* New(simd128_value_t value,
+                           Heap::Space space = Heap::kNew);
+
+  double x() const;
+  double y() const;
+
+  void set_x(double x) const;
+  void set_y(double y) const;
+
+  simd128_value_t value() const;
+  void set_value(simd128_value_t value) const;
+
+  static intptr_t InstanceSize() {
+    return RoundedAllocationSize(sizeof(RawFloat64x2));
+  }
+
+  static intptr_t value_offset() {
+    return OFFSET_OF(RawFloat64x2, value_);
+  }
+
+ private:
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(Float64x2, Instance);
+  friend class Class;
+};
+
+
 class TypedData : public Instance {
  public:
   intptr_t Length() const {
@@ -5987,6 +6049,7 @@
   TYPED_GETTER_SETTER(Float64, double)
   TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
   TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
+  TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
 
 #undef TYPED_GETTER_SETTER
 
@@ -6116,7 +6179,8 @@
   TYPED_GETTER_SETTER(Float32, float)
   TYPED_GETTER_SETTER(Float64, double)
   TYPED_GETTER_SETTER(Float32x4, simd128_value_t)
-  TYPED_GETTER_SETTER(Int32x4, simd128_value_t);
+  TYPED_GETTER_SETTER(Int32x4, simd128_value_t)
+  TYPED_GETTER_SETTER(Float64x2, simd128_value_t)
 
 #undef TYPED_GETTER_SETTER
 
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index fe389c2..c8a046c 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -29,6 +29,9 @@
     mint_class_(Class::null()),
     bigint_class_(Class::null()),
     double_class_(Class::null()),
+    float32x4_type_(Type::null()),
+    int32x4_type_(Type::null()),
+    float64x2_type_(Type::null()),
     string_type_(Type::null()),
     one_byte_string_class_(Class::null()),
     two_byte_string_class_(Class::null()),
@@ -42,6 +45,7 @@
     growable_object_array_class_(Class::null()),
     float32x4_class_(Class::null()),
     int32x4_class_(Class::null()),
+    float64x2_class_(Class::null()),
     typed_data_classes_(Array::null()),
     error_class_(Class::null()),
     stacktrace_class_(Class::null()),
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 710572f..b5f022a 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -208,6 +208,16 @@
   RawType* int32x4_type() const { return int32x4_type_; }
   void set_int32x4_type(const Type& value) { int32x4_type_ = value.raw(); }
 
+  RawClass* float64x2_class() const {
+    return float64x2_class_;
+  }
+  void set_float64x2_class(const Class& value) {
+    float64x2_class_ = value.raw();
+  }
+
+  RawType* float64x2_type() const { return float64x2_type_; }
+  void set_float64x2_type(const Type& value) { float64x2_type_ = value.raw(); }
+
   RawArray* typed_data_classes() const {
     return typed_data_classes_;
   }
@@ -438,6 +448,7 @@
   RawType* double_type_;
   RawType* float32x4_type_;
   RawType* int32x4_type_;
+  RawType* float64x2_type_;
   RawType* string_type_;
   RawClass* one_byte_string_class_;
   RawClass* two_byte_string_class_;
@@ -451,6 +462,7 @@
   RawClass* growable_object_array_class_;
   RawClass* float32x4_class_;
   RawClass* int32x4_class_;
+  RawClass* float64x2_class_;
   RawArray* typed_data_classes_;
   RawClass* error_class_;
   RawClass* stacktrace_class_;
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 2958e47..c376a74 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -4855,6 +4855,19 @@
 }
 
 
+class DartApiScope : public StackResource {
+ public:
+  explicit DartApiScope(Isolate* isolate) : StackResource(isolate) {
+    Dart_EnterScope();
+  }
+  ~DartApiScope() {
+    Dart_ExitScope();
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DartApiScope);
+};
+
 
 RawObject* Parser::CallLibraryTagHandler(Dart_LibraryTag tag,
                                          intptr_t token_pos,
@@ -4872,6 +4885,7 @@
   // Block class finalization attempts when calling into the library
   // tag handler.
   isolate()->BlockClassFinalization();
+  DartApiScope api_scope(isolate());
   Dart_Handle result = handler(tag,
                                Api::NewHandle(isolate(), library_.raw()),
                                Api::NewHandle(isolate(), url.raw()));
@@ -9102,43 +9116,9 @@
 }
 
 
-static RawObject* LookupNameInLibrary(Isolate* isolate,
-                                      const Library& lib,
-                                      const String& name) {
-  Object& obj = Object::Handle(isolate);
-  obj = lib.LookupLocalObject(name);
-  if (!obj.IsNull()) {
-    return obj.raw();
-  }
-  String& accessor_name = String::Handle(isolate, Field::GetterName(name));
-  obj = lib.LookupLocalObject(accessor_name);
-  if (!obj.IsNull()) {
-    return obj.raw();
-  }
-  accessor_name = Field::SetterName(name);
-  obj = lib.LookupLocalObject(accessor_name);
-  return obj.raw();
-}
-
-
-// Resolve a name by checking the global scope of the current
-// library. If not found in the current library, then look in the scopes
-// of all libraries that are imported without a library prefix.
-RawObject* Parser::ResolveNameInCurrentLibraryScope(const String& name) {
-  TRACE_PARSER("ResolveNameInCurrentLibraryScope");
-  HANDLESCOPE(isolate());
-  Object& obj = Object::Handle(isolate(),
-                               LookupNameInLibrary(isolate(), library_, name));
-  if (!obj.IsNull()) {
-    return obj.raw();
-  }
-  return library_.LookupImportedObject(name);
-}
-
-
 RawClass* Parser::ResolveClassInCurrentLibraryScope(const String& name) {
-  const Object& obj =
-      Object::Handle(ResolveNameInCurrentLibraryScope(name));
+  HANDLESCOPE(isolate());
+  const Object& obj = Object::Handle(library_.ResolveName(name));
   if (obj.IsClass()) {
     return Class::Cast(obj).raw();
   }
@@ -9152,8 +9132,8 @@
 AstNode* Parser::ResolveIdentInCurrentLibraryScope(intptr_t ident_pos,
                                                    const String& ident) {
   TRACE_PARSER("ResolveIdentInCurrentLibraryScope");
-  const Object& obj =
-    Object::Handle(ResolveNameInCurrentLibraryScope(ident));
+  HANDLESCOPE(isolate());
+  const Object& obj = Object::Handle(library_.ResolveName(ident));
   if (obj.IsClass()) {
     const Class& cls = Class::Cast(obj);
     return new PrimaryNode(ident_pos, Class::ZoneHandle(cls.raw()));
@@ -9182,17 +9162,10 @@
 }
 
 
-RawObject* Parser::ResolveNameInPrefixScope(const LibraryPrefix& prefix,
-                                            const String& name) {
-  HANDLESCOPE(isolate());
-  return prefix.LookupObject(name);
-}
-
-
 RawClass* Parser::ResolveClassInPrefixScope(const LibraryPrefix& prefix,
                                             const String& name) {
-  const Object& obj =
-      Object::Handle(ResolveNameInPrefixScope(prefix, name));
+  HANDLESCOPE(isolate());
+  const Object& obj = Object::Handle(prefix.LookupObject(name));
   if (obj.IsClass()) {
     return Class::Cast(obj).raw();
   }
@@ -9207,7 +9180,8 @@
                                            const LibraryPrefix& prefix,
                                            const String& ident) {
   TRACE_PARSER("ResolveIdentInPrefixScope");
-  Object& obj = Object::Handle(ResolveNameInPrefixScope(prefix, ident));
+  HANDLESCOPE(isolate());
+  Object& obj = Object::Handle(prefix.LookupObject(ident));
   if (obj.IsNull()) {
     // Unresolved prefixed primary identifier.
     String& qualified_name = String::ZoneHandle(prefix.name());
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 321a56f..1bb7ec4 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -597,12 +597,6 @@
   RawClass* ResolveClassInPrefixScope(const LibraryPrefix& prefix,
                                       const String& name);
 
-  // Find name in the library or prefix scope and return the corresponding
-  // object (field, class, function etc).
-  RawObject* ResolveNameInCurrentLibraryScope(const String& ident);
-  RawObject* ResolveNameInPrefixScope(const LibraryPrefix& prefix,
-                                      const String& name);
-
   AstNode* ResolveIdent(intptr_t ident_pos,
                         const String& ident,
                         bool allow_closure_names);
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 529e733..8b39ec9 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -21,7 +21,7 @@
 
 
 #if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \
-    defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID)
+    defined(TARGET_OS_ANDROID)
   DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
 #else
   DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
diff --git a/runtime/vm/raw_object.cc b/runtime/vm/raw_object.cc
index 3fcb212..f9df8e5 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -792,6 +792,13 @@
 }
 
 
+intptr_t RawFloat64x2::VisitFloat64x2Pointers(
+    RawFloat64x2* raw_obj,
+    ObjectPointerVisitor* visitor) {
+    ASSERT(raw_obj->IsHeapObject());
+    return Float64x2::InstanceSize();
+}
+
 intptr_t RawTypedData::VisitTypedDataPointers(
     RawTypedData* raw_obj, ObjectPointerVisitor* visitor) {
   // Make sure that we got here with the tagged pointer as this.
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 810d637..ef3368c 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -70,6 +70,7 @@
     V(MirrorReference)                                                         \
     V(Float32x4)                                                               \
     V(Int32x4)                                                                 \
+    V(Float64x2)                                                               \
 
 #define CLASS_LIST_ARRAYS(V)                                                   \
   V(Array)                                                                     \
@@ -96,6 +97,7 @@
   V(Float64Array)                                                              \
   V(Float32x4Array)                                                            \
   V(Int32x4Array)                                                              \
+  V(Float64x2Array)                                                            \
 
 #define CLASS_LIST_FOR_HANDLES(V)                                              \
   CLASS_LIST_NO_OBJECT_NOR_STRING_NOR_ARRAY(V)                                 \
@@ -494,7 +496,8 @@
   RawArray* constants_;  // Canonicalized values of this class.
   RawObject* canonical_types_;  // An array of canonicalized types of this class
                                 // or the canonical type.
-  RawArray* invocation_dispatcher_cache_;   // Cache for dispatcher functions.
+  RawArray* invocation_dispatcher_cache_;  // Cache for dispatcher functions.
+  RawArray* cha_codes_;  // CHA optimized codes.
   RawCode* allocation_stub_;  // Stub code for allocation of instances.
   RawObject** to() {
     return reinterpret_cast<RawObject**>(&ptr()->allocation_stub_);
@@ -778,6 +781,7 @@
   RawScript* script_;
   RawString* private_key_;
   RawArray* dictionary_;         // Top-level names in this library.
+  RawArray* resolved_names_;     // Cache of resolved names in library scope.
   RawGrowableObjectArray* metadata_;  // Metadata on classes, methods etc.
   RawArray* anonymous_classes_;  // Classes containing top-level elements.
   RawArray* imports_;            // List of Namespaces imported without prefix.
@@ -1452,6 +1456,18 @@
 };
 
 
+class RawFloat64x2 : public RawInstance {
+  RAW_HEAP_OBJECT_IMPLEMENTATION(Float64x2);
+
+  double value_[2];
+
+  friend class SnapshotReader;
+ public:
+  double x() const { return value_[0]; }
+  double y() const { return value_[1]; }
+};
+
+
 // Define an aliases for intptr_t.
 #if defined(ARCH_IS_32_BIT)
 #define kIntPtrCid kTypedDataInt32ArrayCid
@@ -1677,9 +1693,10 @@
          kTypedDataFloat64ArrayCid == kTypedDataInt8ArrayCid + 10 &&
          kTypedDataFloat32x4ArrayCid == kTypedDataInt8ArrayCid + 11 &&
          kTypedDataInt32x4ArrayCid == kTypedDataInt8ArrayCid + 12 &&
-         kTypedDataInt8ArrayViewCid == kTypedDataInt8ArrayCid + 13);
+         kTypedDataFloat64x2ArrayCid == kTypedDataInt8ArrayCid + 13 &&
+         kTypedDataInt8ArrayViewCid == kTypedDataInt8ArrayCid + 14);
   return (index >= kTypedDataInt8ArrayCid &&
-          index <= kTypedDataInt32x4ArrayCid);
+          index <= kTypedDataFloat64x2ArrayCid);
 }
 
 
@@ -1697,8 +1714,9 @@
          kTypedDataFloat64ArrayViewCid == kTypedDataInt8ArrayViewCid + 10 &&
          kTypedDataFloat32x4ArrayViewCid == kTypedDataInt8ArrayViewCid + 11 &&
          kTypedDataInt32x4ArrayViewCid == kTypedDataInt8ArrayViewCid + 12 &&
-         kByteDataViewCid == kTypedDataInt8ArrayViewCid + 13 &&
-         kExternalTypedDataInt8ArrayCid == kTypedDataInt8ArrayViewCid + 14);
+         kTypedDataFloat64x2ArrayViewCid == kTypedDataInt8ArrayViewCid + 13 &&
+         kByteDataViewCid == kTypedDataInt8ArrayViewCid + 14 &&
+         kExternalTypedDataInt8ArrayCid == kTypedDataInt8ArrayViewCid + 15);
   return (index >= kTypedDataInt8ArrayViewCid &&
           index <= kByteDataViewCid);
 }
@@ -1730,9 +1748,11 @@
           kExternalTypedDataInt8ArrayCid + 11) &&
          (kExternalTypedDataInt32x4ArrayCid ==
           kExternalTypedDataInt8ArrayCid + 12) &&
-         (kNullCid == kExternalTypedDataInt8ArrayCid + 13));
+         (kExternalTypedDataFloat64x2ArrayCid ==
+          kExternalTypedDataInt8ArrayCid + 13) &&
+         (kNullCid == kExternalTypedDataInt8ArrayCid + 14));
   return (index >= kExternalTypedDataInt8ArrayCid &&
-          index <= kExternalTypedDataInt32x4ArrayCid);
+          index <= kExternalTypedDataFloat64x2ArrayCid);
 }
 
 
@@ -1767,9 +1787,9 @@
 
 inline intptr_t RawObject::NumberOfTypedDataClasses() {
   // Make sure this is updated when new TypedData types are added.
-  ASSERT(kTypedDataInt8ArrayViewCid == kTypedDataInt8ArrayCid + 13);
-  ASSERT(kExternalTypedDataInt8ArrayCid == kTypedDataInt8ArrayViewCid + 14);
-  ASSERT(kNullCid == kExternalTypedDataInt8ArrayCid + 13);
+  ASSERT(kTypedDataInt8ArrayViewCid == kTypedDataInt8ArrayCid + 14);
+  ASSERT(kExternalTypedDataInt8ArrayCid == kTypedDataInt8ArrayViewCid + 15);
+  ASSERT(kNullCid == kExternalTypedDataInt8ArrayCid + 14);
   return (kNullCid - kTypedDataInt8ArrayCid);
 }
 
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index a34039c..e46625b 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -2209,9 +2209,9 @@
 
 
 RawFloat32x4* Float32x4::ReadFrom(SnapshotReader* reader,
-                                            intptr_t object_id,
-                                            intptr_t tags,
-                                            Snapshot::Kind kind) {
+                                  intptr_t object_id,
+                                  intptr_t tags,
+                                  Snapshot::Kind kind) {
   ASSERT(reader != NULL);
   // Read the values.
   float value0 = reader->Read<float>();
@@ -2235,8 +2235,8 @@
 
 
 void RawFloat32x4::WriteTo(SnapshotWriter* writer,
-                                intptr_t object_id,
-                                Snapshot::Kind kind) {
+                           intptr_t object_id,
+                           Snapshot::Kind kind) {
   ASSERT(writer != NULL);
 
   // Write out the serialization header value for this object.
@@ -2255,9 +2255,9 @@
 
 
 RawInt32x4* Int32x4::ReadFrom(SnapshotReader* reader,
-                                      intptr_t object_id,
-                                      intptr_t tags,
-                                      Snapshot::Kind kind) {
+                              intptr_t object_id,
+                              intptr_t tags,
+                              Snapshot::Kind kind) {
   ASSERT(reader != NULL);
   // Read the values.
   uint32_t value0 = reader->Read<uint32_t>();
@@ -2281,8 +2281,8 @@
 
 
 void RawInt32x4::WriteTo(SnapshotWriter* writer,
-                             intptr_t object_id,
-                             Snapshot::Kind kind) {
+                         intptr_t object_id,
+                         Snapshot::Kind kind) {
   ASSERT(writer != NULL);
 
   // Write out the serialization header value for this object.
@@ -2300,6 +2300,48 @@
 }
 
 
+RawFloat64x2* Float64x2::ReadFrom(SnapshotReader* reader,
+                                  intptr_t object_id,
+                                  intptr_t tags,
+                                  Snapshot::Kind kind) {
+  ASSERT(reader != NULL);
+  // Read the values.
+  double value0 = reader->Read<double>();
+  double value1 = reader->Read<double>();
+
+  // Create a Float64x2 object.
+  Float64x2& simd = Float64x2::ZoneHandle(reader->isolate(),
+                                          Float64x2::null());
+  if (kind == Snapshot::kFull) {
+    simd = reader->NewFloat64x2(value0, value1);
+  } else {
+    simd = Float64x2::New(value0, value1, HEAP_SPACE(kind));
+  }
+  reader->AddBackRef(object_id, &simd, kIsDeserialized);
+  // Set the object tags.
+  simd.set_tags(tags);
+  return simd.raw();
+}
+
+
+void RawFloat64x2::WriteTo(SnapshotWriter* writer,
+                           intptr_t object_id,
+                           Snapshot::Kind kind) {
+  ASSERT(writer != NULL);
+
+  // Write out the serialization header value for this object.
+  writer->WriteInlinedObjectHeader(object_id);
+
+  // Write out the class and tags information.
+  writer->WriteIndexedObject(kFloat64x2Cid);
+  writer->WriteIntptrValue(writer->GetObjectTags(this));
+
+  // Write out the float values.
+  writer->Write<double>(ptr()->value_[0]);
+  writer->Write<double>(ptr()->value_[1]);
+}
+
+
 #define TYPED_DATA_READ(setter, type)                                          \
   for (intptr_t i = 0; i < lengthInBytes; i += element_size) {                 \
     result.Set##setter(i, reader->Read<type>());                               \
diff --git a/runtime/vm/resolver.cc b/runtime/vm/resolver.cc
index fcbed02..11cd7e5 100644
--- a/runtime/vm/resolver.cc
+++ b/runtime/vm/resolver.cc
@@ -150,7 +150,7 @@
   Function& function = Function::Handle();
   if (class_name.IsNull() || (class_name.Length() == 0)) {
     // Check if we are referring to a top level function.
-    const Object& object = Object::Handle(library.LookupObject(function_name));
+    const Object& object = Object::Handle(library.ResolveName(function_name));
     if (!object.IsNull() && object.IsFunction()) {
       function ^= object.raw();
       if (!function.AreValidArguments(num_arguments, argument_names, NULL)) {
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
index 7c2fee2..e89cc65 100644
--- a/runtime/vm/service_test.cc
+++ b/runtime/vm/service_test.cc
@@ -72,6 +72,25 @@
 }
 
 
+// Search for the formatted string in buff.
+static void ExpectSubstringF(const char* buff, const char* fmt, ...) {
+  Isolate* isolate = Isolate::Current();
+
+  va_list args;
+  va_start(args, fmt);
+  intptr_t len = OS::VSNPrint(NULL, 0, fmt, args);
+  va_end(args);
+
+  char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+  va_list args2;
+  va_start(args2, fmt);
+  OS::VSNPrint(buffer, (len + 1), fmt, args2);
+  va_end(args2);
+
+  EXPECT_SUBSTRING(buffer, buff);
+}
+
+
 static RawFunction* GetFunction(const Class& cls, const char* name) {
   const Function& result = Function::Handle(cls.LookupDynamicFunction(
       String::Handle(String::New(name))));
@@ -331,87 +350,59 @@
   service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "'], [], []]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
-      "{\"type\":\"Class\",\"id\":\"classes\\/1009\",\"name\":\"A\","
-      "\"user_name\":\"A\",\"implemented\":false,\"abstract\":false,"
-      "\"patch\":false,\"finalized\":true,\"const\":false,\"super\":"
-      "{\"type\":\"@Class\",\"id\":\"classes\\/35\",\"name\":\"Object\","
-      "\"user_name\":\"Object\"},\"library\":{\"type\":\"@Library\",\"id\":"
-      "\"libraries\\/12\",\"name\":\"\",\"user_name\":\"dart:test-lib\"},"
-      "\"fields\":[{\"type\":\"@Field\",\"id\":\"classes\\/1009\\/fields\\/0\","
-      "\"name\":\"a\",\"user_name\":\"a\",\"owner\":{\"type\":\"@Class\","
-      "\"id\":\"classes\\/1009\",\"name\":\"A\",\"user_name\":\"A\"},"
-      "\"declared_type\":{\"type\":\"@Class\",\"id\":\"classes\\/106\","
-      "\"name\":\"dynamic\",\"user_name\":\"dynamic\"},\"static\":false,"
-      "\"final\":false,\"const\":false}],\"functions\":["
-      "{\"type\":\"@Function\",\"id\":\"classes\\/1009\\/functions\\/0\","
-      "\"name\":\"get:a\",\"user_name\":\"A.a\"},{\"type\":\"@Function\","
-      "\"id\":\"classes\\/1009\\/functions\\/1\",\"name\":\"set:a\","
-      "\"user_name\":\"A.a=\"},{\"type\":\"@Function\",\"id\":"
-      "\"classes\\/1009\\/functions\\/2\",\"name\":\"b\",\"user_name\":\"A.b\"}"
-      ",{\"type\":\"@Function\",\"id\":\"classes\\/1009\\/functions\\/3\","
-      "\"name\":\"c\",\"user_name\":\"A.c\"},{\"type\":\"@Function\",\"id\":"
-      "\"classes\\/1009\\/functions\\/4\",\"name\":\"A.\",\"user_name\":"
-      "\"A.A\"}]}",
-      handler.msg());
 
-  // Request function 0 from class A.
+  EXPECT_SUBSTRING("\"type\":\"Class\"", handler.msg());
+  ExpectSubstringF(handler.msg(),
+                   "\"id\":\"classes\\/%" Pd "\",\"name\":\"A\",", cid);
+
   service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '0'],"
                               "[], []]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
-    "{\"type\":\"Function\",\"id\":\"classes\\/1009\\/functions\\/0\",\"name\":"
-    "\"get:a\",\"user_name\":\"A.a\",\"is_static\":false,\"is_const\":false,"
-    "\"is_optimizable\":true,\"is_inlinable\":false,\"kind\":"
-    "\"kImplicitGetter\",\"unoptimized_code\":{\"type\":\"null\"},"
-    "\"usage_counter\":0,\"optimized_call_site_count\":0,\"code\":"
-    "{\"type\":\"null\"},\"deoptimizations\":0}", handler.msg());
+  EXPECT_SUBSTRING("\"type\":\"Function\"", handler.msg());
+  ExpectSubstringF(handler.msg(),
+                   "\"id\":\"classes\\/%" Pd "\\/functions\\/0\","
+                   "\"name\":\"get:a\",", cid);
 
   // Request field 0 from class A.
   service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '0'],"
                               "[], []]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
-    "{\"type\":\"Field\",\"id\":\"classes\\/1009\\/fields\\/0\",\"name\":\"a\","
-    "\"user_name\":\"a\",\"owner\":{\"type\":\"@Class\",\"id\":"
-    "\"classes\\/1009\",\"name\":\"A\",\"user_name\":\"A\"},\"declared_type\":"
-    "{\"type\":\"@Class\",\"id\":\"classes\\/106\",\"name\":\"dynamic\","
-    "\"user_name\":\"dynamic\"},\"static\":false,\"final\":false,\"const\":"
-    "false,\"guard_nullable\":true,\"guard_class\":{\"type\":\"@Class\","
-    "\"id\":\"classes\\/105\",\"name\":\"Null\",\"user_name\":\"Null\"},"
-    "\"guard_length\":\"variable\"}", handler.msg());
+  EXPECT_SUBSTRING("\"type\":\"Field\"", handler.msg());
+  ExpectSubstringF(handler.msg(),
+                   "\"id\":\"classes\\/%" Pd "\\/fields\\/0\","
+                   "\"name\":\"a\",", cid);
 
   // Invalid sub command.
   service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'huh', '0'],"
                               "[], []]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
+  ExpectSubstringF(handler.msg(),
     "{\"type\":\"Error\",\"text\":\"Invalid sub collection huh\",\"message\":"
-    "{\"arguments\":[\"classes\",\"1009\",\"huh\",\"0\"],\"option_keys\":[],"
-    "\"option_values\":[]}}", handler.msg());
+    "{\"arguments\":[\"classes\",\"%" Pd "\",\"huh\",\"0\"],\"option_keys\":[],"
+    "\"option_values\":[]}}", cid);
 
   // Invalid field request.
   service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'fields', '9'],"
                               "[], []]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
+  ExpectSubstringF(handler.msg(),
     "{\"type\":\"Error\",\"text\":\"Field 9 not found\","
-    "\"message\":{\"arguments\":[\"classes\",\"1009\",\"fields\",\"9\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", handler.msg());
+    "\"message\":{\"arguments\":[\"classes\",\"%" Pd "\",\"fields\",\"9\"],"
+    "\"option_keys\":[],\"option_values\":[]}}", cid);
 
   // Invalid function request.
   service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '9'],"
                               "[], []]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
+  ExpectSubstringF(handler.msg(),
     "{\"type\":\"Error\",\"text\":\"Function 9 not found\","
-    "\"message\":{\"arguments\":[\"classes\",\"1009\",\"functions\",\"9\"],"
-    "\"option_keys\":[],\"option_values\":[]}}", handler.msg());
+    "\"message\":{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"9\"],"
+    "\"option_keys\":[],\"option_values\":[]}}", cid);
 
 
   // Invalid field subcommand.
@@ -419,22 +410,20 @@
                              ",[], []]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
+  ExpectSubstringF(handler.msg(),
     "{\"type\":\"Error\",\"text\":\"Command too long\",\"message\":"
-    "{\"arguments\":[\"classes\",\"1009\",\"fields\",\"9\",\"x\"],"
-    "\"option_keys\":[],\"option_values\":[]}}",
-    handler.msg());
+    "{\"arguments\":[\"classes\",\"%" Pd "\",\"fields\",\"9\",\"x\"],"
+    "\"option_keys\":[],\"option_values\":[]}}", cid);
 
   // Invalid function request.
   service_msg = EvalF(h_lib, "[port, ['classes', '%" Pd "', 'functions', '9',"
                              "'x'], [], []]", cid);
   Service::HandleIsolateMessage(isolate, service_msg);
   handler.HandleNextMessage();
-  EXPECT_STREQ(
+  ExpectSubstringF(handler.msg(),
     "{\"type\":\"Error\",\"text\":\"Command too long\",\"message\":"
-    "{\"arguments\":[\"classes\",\"1009\",\"functions\",\"9\",\"x\"],"
-    "\"option_keys\":[],\"option_values\":[]}}",
-    handler.msg());
+    "{\"arguments\":[\"classes\",\"%" Pd "\",\"functions\",\"9\",\"x\"],"
+    "\"option_keys\":[],\"option_values\":[]}}", cid);
 }
 
 
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index d029476..c3cf071 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -648,6 +648,18 @@
 }
 
 
+RawFloat64x2* SnapshotReader::NewFloat64x2(double v0, double v1) {
+  ASSERT(kind_ == Snapshot::kFull);
+  ASSERT(isolate()->no_gc_scope_depth() != 0);
+  cls_ = object_store()->float64x2_class();
+  RawFloat64x2* obj = reinterpret_cast<RawFloat64x2*>(
+      AllocateUninitialized(cls_, Float64x2::InstanceSize()));
+  obj->ptr()->value_[0] = v0;
+  obj->ptr()->value_[1] = v1;
+  return obj;
+}
+
+
 RawApiError* SnapshotReader::NewApiError() {
   ALLOC_NEW_OBJECT(ApiError, Object::api_error_class());
 }
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index cc001386..9aa5bc3 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -45,6 +45,7 @@
 class RawFunction;
 class RawGrowableObjectArray;
 class RawFloat32x4;
+class RawFloat64x2;
 class RawInt32x4;
 class RawImmutableArray;
 class RawLanguageError;
@@ -275,6 +276,7 @@
   RawGrowableObjectArray* NewGrowableObjectArray();
   RawFloat32x4* NewFloat32x4(float v0, float v1, float v2, float v3);
   RawInt32x4* NewInt32x4(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3);
+  RawFloat64x2* NewFloat64x2(double v0, double v1);
   RawApiError* NewApiError();
   RawLanguageError* NewLanguageError();
   RawObject* NewInteger(int64_t value);
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 3907235..8052a1a 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -136,8 +136,10 @@
   V(Int, "int")                                                                \
   V(Double, "double")                                                          \
   V(_Float32x4, "_Float32x4")                                                  \
+  V(_Float64x2, "_Float64x2")                                                  \
   V(_Int32x4, "_Int32x4")                                                      \
   V(Float32x4, "Float32x4")                                                    \
+  V(Float64x2, "Float64x2")                                                    \
   V(Int32x4, "Int32x4")                                                        \
   V(Int8List, "Int8List")                                                      \
   V(Int8ListFactory, "Int8List.")                                              \
@@ -161,6 +163,8 @@
   V(Float32x4ListFactory, "Float32x4List.")                                    \
   V(Int32x4List, "Int32x4List")                                                \
   V(Int32x4ListFactory, "Int32x4List.")                                        \
+  V(Float64x2List, "Float64x2List")                                            \
+  V(Float64x2ListFactory, "Float64x2List.")                                    \
   V(Float32List, "Float32List")                                                \
   V(Float32ListFactory, "Float32List.")                                        \
   V(Float64List, "Float64List")                                                \
@@ -187,6 +191,8 @@
   V(_Float32x4ArrayFactory, "_Float32x4Array.")                                \
   V(_Int32x4Array, "_Int32x4Array")                                            \
   V(_Int32x4ArrayFactory, "_Int32x4Array.")                                    \
+  V(_Float64x2Array, "_Float64x2Array")                                        \
+  V(_Float64x2ArrayFactory, "_Float64x2Array.")                                \
   V(_Float32Array, "_Float32Array")                                            \
   V(_Float32ArrayFactory, "_Float32Array.")                                    \
   V(_Float64Array, "_Float64Array")                                            \
@@ -204,6 +210,7 @@
   V(_Float64ArrayView, "_Float64ArrayView")                                    \
   V(_Float32x4ArrayView, "_Float32x4ArrayView")                                \
   V(_Int32x4ArrayView, "_Int32x4ArrayView")                                    \
+  V(_Float64x2ArrayView, "_Float64x2ArrayView")                                \
   V(_ExternalInt8Array, "_ExternalInt8Array")                                  \
   V(_ExternalUint8Array, "_ExternalUint8Array")                                \
   V(_ExternalUint8ClampedArray, "_ExternalUint8ClampedArray")                  \
@@ -217,6 +224,7 @@
   V(_ExternalInt32x4Array, "_ExternalInt32x4Array")                            \
   V(_ExternalFloat32Array, "_ExternalFloat32Array")                            \
   V(_ExternalFloat64Array, "_ExternalFloat64Array")                            \
+  V(_ExternalFloat64x2Array, "_ExternalFloat64x2Array")                        \
   V(ByteData, "ByteData")                                                      \
   V(ByteDataDot, "ByteData.")                                                  \
   V(ByteDataDotview, "ByteData.view")                                          \
diff --git a/sdk/bin/dart2js.bat b/sdk/bin/dart2js.bat
index 8951a02..ed460c8 100644
--- a/sdk/bin/dart2js.bat
+++ b/sdk/bin/dart2js.bat
@@ -36,7 +36,7 @@
 set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% --heap_growth_rate=512
 
 rem We allow extra vm options to be passed in through an environment variable.
-if not _%DART_VM_OPTIONS%_ == __ (
+if not "_%DART_VM_OPTIONS%_" == "__" (
   set EXTRA_VM_OPTIONS=%EXTRA_VM_OPTIONS% %DART_VM_OPTIONS%
 )
 
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index efb75b8..d0bb37b 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -17,6 +17,8 @@
    * Contains the initial value of fields. Must contain all static and global
    * initializations of const fields. May contain eagerly compiled values for
    * statics and instance fields.
+   *
+   * Invariant: The keys in this map are declarations.
    */
   final Map<VariableElement, Constant> initialVariableValues;
 
@@ -44,7 +46,7 @@
   }
 
   Constant getConstantForVariable(VariableElement element) {
-    return initialVariableValues[element];
+    return initialVariableValues[element.declaration];
   }
 
   /**
@@ -61,8 +63,8 @@
    */
   Constant compileVariable(VariableElement element, {bool isConst: false}) {
     return measure(() {
-      if (initialVariableValues.containsKey(element)) {
-        Constant result = initialVariableValues[element];
+      if (initialVariableValues.containsKey(element.declaration)) {
+        Constant result = initialVariableValues[element.declaration];
         return result;
       }
       Element currentElement = element;
@@ -145,7 +147,7 @@
         }
       }
       if (value != null) {
-        initialVariableValues[element] = value;
+        initialVariableValues[element.declaration] = value;
       } else {
         assert(!isConst);
         lazyStatics.add(element);
@@ -223,7 +225,7 @@
   }
 
   Constant getInitialValueFor(VariableElement element) {
-    Constant initialValue = initialVariableValues[element];
+    Constant initialValue = initialVariableValues[element.declaration];
     if (initialValue == null) {
       compiler.internalError("No initial value for given element",
                              element: element);
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index d13da55..2551bf8 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -499,10 +499,7 @@
       return f();
     } on SpannableAssertionFailure catch (ex) {
       if (!hasCrashed) {
-        String message = (ex.message != null) ? tryToString(ex.message)
-                                              : tryToString(ex);
-        SourceSpan span = spanFromSpannable(ex.node);
-        reportError(ex.node, MessageKind.GENERIC, {'text': message});
+        reportAssertionFailure(ex);
         pleaseReportCrash();
       }
       hasCrashed = true;
@@ -1397,6 +1394,13 @@
 
   void reportDiagnostic(SourceSpan span, String message, api.Diagnostic kind);
 
+  void reportAssertionFailure(SpannableAssertionFailure ex) {
+    String message = (ex.message != null) ? tryToString(ex.message)
+                                          : tryToString(ex);
+    SourceSpan span = spanFromSpannable(ex.node);
+    reportError(ex.node, MessageKind.GENERIC, {'text': message});
+  }
+
   SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
     if (begin == null || end == null) {
       // TODO(ahe): We can almost always do better. Often it is only
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
index 6b885d6..14a2cc9 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
@@ -117,6 +117,9 @@
   visitLiteralString(LiteralString node) => new LiteralString(
       node.token, node.dartString);
 
+  visitMetadata(Metadata node) => new Metadata(
+      node.token, visit(node.expression));
+
   visitMixinApplication(MixinApplication node) => new MixinApplication(
       visit(node.superclass), visit(node.mixins));
 
@@ -213,8 +216,10 @@
   visitTypeVariable(TypeVariable node) => new TypeVariable(
       visit(node.name), visit(node.bound));
 
-  visitVariableDefinitions(VariableDefinitions node) => new VariableDefinitions(
-      visit(node.type), visit(node.modifiers), visit(node.definitions));
+  visitVariableDefinitions(VariableDefinitions node) =>
+      new VariableDefinitions.forParameter(
+          visit(node.metadata), visit(node.type),
+          visit(node.modifiers), visit(node.definitions));
 
   visitWhile(While node) => new While(
       visit(node.condition), visit(node.body), node.whileKeyword);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index a61dac8..ee6f15c 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -363,7 +363,7 @@
   TypeDeclarationElement get element;
 
   /// Creates a new instance of this type using the provided type arguments.
-  GenericType _createType(Link<DartType> newTypeArguments);
+  GenericType createInstantiation(Link<DartType> newTypeArguments);
 
   DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
     if (typeArguments.isEmpty) {
@@ -379,7 +379,7 @@
         Types.substTypes(typeArguments, arguments, parameters);
     if (!identical(typeArguments, newTypeArguments)) {
       // Create a new type only if necessary.
-      return _createType(newTypeArguments);
+      return createInstantiation(newTypeArguments);
     }
     return this;
   }
@@ -465,7 +465,7 @@
 
   String get name => element.name;
 
-  InterfaceType _createType(Link<DartType> newTypeArguments) {
+  InterfaceType createInstantiation(Link<DartType> newTypeArguments) {
     return new InterfaceType(element, newTypeArguments);
   }
 
@@ -798,7 +798,7 @@
               [Link<DartType> typeArguments = const Link<DartType>()])
       : super(typeArguments);
 
-  TypedefType _createType(Link<DartType> newTypeArguments) {
+  TypedefType createInstantiation(Link<DartType> newTypeArguments) {
     return new TypedefType(element, newTypeArguments);
   }
 
@@ -1216,11 +1216,17 @@
   bool visitInterfaceType(InterfaceType t, DartType s) {
     if (super.visitInterfaceType(t, s)) return true;
 
-    lookupCall(type) => type.lookupMember(Compiler.CALL_OPERATOR_NAME);
+    InterfaceTypeMember lookupCall(type) =>
+        type.lookupMember(Compiler.CALL_OPERATOR_NAME);
+
+    bool hasCallMethod(type) {
+      InterfaceTypeMember member = lookupCall(type);
+      return member != null && member.element.isFunction();
+    }
 
     if (s is InterfaceType &&
         s.element == compiler.functionClass &&
-        lookupCall(t) != null) {
+        hasCallMethod(t)) {
       return true;
     } else if (s is FunctionType) {
       InterfaceTypeMember call = lookupCall(t);
@@ -1717,7 +1723,7 @@
       element.typeVariables.forEach((TypeVariableType typeVariable) {
         typeArguments.addLast(constraintMap[typeVariable]);
       });
-      return element.thisType._createType(typeArguments.toLink());
+      return element.thisType.createInstantiation(typeArguments.toLink());
     }
     return null;
   }
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 53d6650..3243e90 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -907,6 +907,11 @@
 
   bool isObject(Compiler compiler);
   bool isSubclassOf(ClassElement cls);
+  /// Returns true if `this` explicitly/nominally implements [intrface].
+  ///
+  /// Note that, if [intrface] is the `Function` class, this method returns
+  /// falso for a class that has a `call` method but does not explicitly
+  /// implement `Function`.
   bool implementsInterface(ClassElement intrface);
   bool hasFieldShadowedBy(Element fieldMember);
 
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index b52189b..8701835 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -1140,6 +1140,12 @@
         variables = null,
         super(name, kind, enclosing);
 
+  void addMetadata(MetadataAnnotation metadata) {
+    variables.addMetadata(metadata);
+  }
+
+  Link<MetadataAnnotation> get metadata => variables.metadata;
+
   Node parseNode(DiagnosticListener listener) {
     if (cachedNode != null) return cachedNode;
     VariableDefinitions definitions = variables.parseNode(listener);
@@ -1169,6 +1175,20 @@
   Token position() => findMyName(variables.position());
 
   accept(ElementVisitor visitor) => visitor.visitVariableElement(this);
+
+  // TODO(johnniwinther): Move the patch/origin implementation to a parameter
+  // specific element when added.
+
+  /**
+   * A function declaration that should be parsed instead of the current one.
+   * The patch should be parsed as if it was in the current scope. Its
+   * signature must match this function's signature.
+   */
+  VariableElementX patch = null;
+  VariableElementX origin = null;
+
+  bool get isPatch => origin != null;
+  bool get isPatched => patch != null;
 }
 
 class FieldElementX extends VariableElementX implements FieldElement {
@@ -2461,7 +2481,7 @@
    * The compile-time constant which this annotation resolves to.
    * In the mirror system, this would be an object mirror.
    */
-  Constant get value;
+  Constant value;
   Element annotatedElement;
   int resolutionState;
 
@@ -2479,5 +2499,20 @@
     return this;
   }
 
+  Node parseNode(DiagnosticListener listener);
+
   String toString() => 'MetadataAnnotation($value, $resolutionState)';
 }
+
+/// Metadata annotation on a parameter.
+class ParameterMetadataAnnotation extends MetadataAnnotationX {
+  final Metadata metadata;
+
+  ParameterMetadataAnnotation(Metadata this.metadata);
+
+  Node parseNode(DiagnosticListener listener) => metadata.expression;
+
+  Token get beginToken => metadata.getBeginToken();
+
+  Token get endToken => metadata.getEndToken();
+}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
index 6890de7..29d898b 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
@@ -47,7 +47,7 @@
                  Element enclosing,
                  [T elementType, int length]);
 
-  T allocateMap(T keyType, T valueType, T type);
+  T allocateMap(T type, Node node, Element element, [T keyType, T valueType]);
 
   T allocateClosure(Node node, Element element);
 
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart
index 1d2d063..df9630a 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart
@@ -9,7 +9,7 @@
  * change the element type of the list, or let the list escape to code
  * that might change the element type.
  */
-Set<String> okSelectorsSet = new Set<String>.from(
+Set<String> okListSelectorsSet = new Set<String>.from(
   const <String>[
     // From Object.
     '==',
@@ -127,31 +127,33 @@
 
 
 class ListTracerVisitor extends TracerVisitor {
-  // The list of found assignments to the container.
-  final List<TypeInformation> assignments = <TypeInformation>[];
+  // The [List] of found assignments to the list.
+  List<TypeInformation> assignments = <TypeInformation>[];
   bool callsGrowableMethod = false;
-  
+
   ListTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
 
-  List<TypeInformation> run() {
+  /**
+   * Returns [true] if the analysis completed successfully, [false] if it
+   * bailed out. In the former case, [assignments] holds a list of
+   * [TypeInformation] nodes that flow into the element type of this list.
+   */
+  bool run() {
     analyze();
-    ListTypeInformation container = tracedType;
+    ListTypeInformation list = tracedType;
     if (continueAnalyzing) {
-      if (!callsGrowableMethod && container.inferredLength == null) {
-        container.inferredLength = container.originalLength;
+      if (!callsGrowableMethod && list.inferredLength == null) {
+        list.inferredLength = list.originalLength;
       }
-      container.flowsInto.addAll(flowsInto);
-      return assignments;
+      list.flowsInto.addAll(flowsInto);
+      return true;
     } else {
       callsGrowableMethod = true;
-      return null;
+      assignments = null;
+      return false;
     }
   }
 
-  visitMapTypeInformation(MapTypeInformation info) {
-    bailout('Stored in a map');
-  }
-
   visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
     bailout('Passed to a closure');
   }
@@ -169,7 +171,7 @@
     Selector selector = info.selector;
     String selectorName = selector.name;
     if (currentUser == info.receiver) {
-      if (!okSelectorsSet.contains(selectorName)) {
+      if (!okListSelectorsSet.contains(selectorName)) {
         if (selector.isCall()) {
           int positionalLength = info.arguments.positional.length;
           if (selectorName == 'add') {
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/map_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/map_tracer.dart
new file mode 100644
index 0000000..595505a
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/map_tracer.dart
@@ -0,0 +1,111 @@
+// Copyright (c) 2014, 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 type_graph_inferrer;
+
+Set<String> okMapSelectorsSet = new Set.from(
+    const <String>[
+      "[]",
+      "isEmpty",
+      "isNotEmpty",
+      "keys",
+      "length",
+      "values",
+      "clear",
+      "containsKey",
+      "containsValue",
+      "forEach",
+      "remove"]);
+
+class MapTracerVisitor extends TracerVisitor {
+  List<TypeInformation> keyAssignments = <TypeInformation>[];
+  List<TypeInformation> valueAssignments = <TypeInformation>[];
+
+  MapTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
+
+  /**
+   * Returns [true] if the analysis completed successfully, [false]
+   * if it bailed out. In the former case, [keyAssignments] and
+   * [valueAssignments] hold a list of [TypeInformation] nodes that
+   * flow into the key and value types of this map.
+   */
+  bool run() {
+    analyze();
+    MapTypeInformation map = tracedType;
+    if (continueAnalyzing) {
+      map.flowsInto.addAll(flowsInto);
+      return true;
+    }
+    keyAssignments = valueAssignments = null;
+    return false;
+  }
+
+  visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
+    bailout('Passed to a closure');
+  }
+
+  visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
+    super.visitStaticCallSiteTypeInformation(info);
+    Element called = info.calledElement;
+    if (called.isForeign(compiler) && called.name == 'JS') {
+      bailout('Used in JS ${info.call}');
+    }
+  }
+
+  visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
+    super.visitDynamicCallSiteTypeInformation(info);
+    Selector selector = info.selector;
+    String selectorName = selector.name;
+    if (currentUser == info.receiver) {
+      if (!okMapSelectorsSet.contains(selectorName)) {
+        if (selector.isCall()) {
+          int positionalLength = info.arguments.positional.length;
+          if (selectorName == 'addAll') {
+            // All keys and values from the argument flow into
+            // the map.
+            TypeInformation map = info.arguments.positional[0];
+            if (map is MapTypeInformation) {
+              keyAssignments.add(map.keyType);
+              valueAssignments.add(map.valueType);
+            } else {
+              // If we could select a component from a [TypeInformation],
+              // like the keytype or valuetype in this case, we could
+              // propagate more here.
+              // TODO(herhut): implement selection on [TypeInformation].
+              bailout('Adding map with unknown typeinfo to current map');
+            }
+          } else if (selectorName == 'putIfAbsent') {
+            // The first argument is a new key, the result type of
+            // the second argument becomes a new value.
+            // Unfortunately, the type information does not
+            // explicitly track the return type, yet, so we have
+            // to go to dynamic.
+            // TODO(herhut,16507): Use return type of closure in
+            // Map.putIfAbsent.
+            keyAssignments.add(info.arguments.positional[0]);
+            valueAssignments.add(inferrer.types.dynamicType);
+          } else {
+            // It would be nice to handle [Map.keys] and [Map.values], too.
+            // However, currently those calls do not trigger the creation
+            // of a [ListTypeInformation], so I have nowhere to propagate
+            // that information.
+            // TODO(herhut): add support for Map.keys and Map.values.
+            bailout('Map used in a not-ok selector');
+            return;
+          }
+        } else if (selector.isIndexSet()) {
+          keyAssignments.add(info.arguments.positional[0]);
+          valueAssignments.add(info.arguments.positional[1]);
+        } else if (!selector.isIndex()) {
+          bailout('Map used in a not-ok selector');
+          return;
+        }
+      }
+    } else if (selector.isCall()
+               && !info.targets.every((element) => element.isFunction())) {
+      bailout('Passed to a closure');
+      return;
+    }
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
index 380a472..98a6589 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
@@ -6,7 +6,7 @@
 
 // A set of selectors we know do not escape the elements inside the
 // list.
-Set<String> doesNotEscapeElementSet = new Set<String>.from(
+Set<String> doesNotEscapeListSet = new Set<String>.from(
   const <String>[
     // From Object.
     '==',
@@ -46,6 +46,23 @@
     'checkGrowable',
   ]);
 
+Set<String> doesNotEscapeMapSet = new Set<String>.from(
+  const <String>[
+    // From Object.
+    '==',
+    'hashCode',
+    'toString',
+    'noSuchMethod',
+    'runtimeType',
+    // from Map.
+    'isEmpty',
+    'isNotEmpty',
+    'length',
+    'clear',
+    'containsKey',
+    'containsValue'
+  ]);
+
 abstract class TracerVisitor implements TypeInformationVisitor {
   final TypeInformation tracedType;
   final TypeGraphInferrerEngine inferrer;
@@ -61,12 +78,16 @@
   // contain the container.
   final List<TypeInformation> workList = <TypeInformation>[];
 
-  // Work list of containers to analyze after analyzing the users of a
-  // [TypeInformation] that may be [container]. We know [container]
-  // has been stored in these containers and we must check how
-  // [container] escapes from these containers.
-  final List<ListTypeInformation> containersToAnalyze =
+  // Work list of lists to analyze after analyzing the users of a
+  // [TypeInformation]. We know the [tracedType] has been stored in these
+  // lists and we must check how it escapes from these lists.
+  final List<ListTypeInformation> listsToAnalyze =
       <ListTypeInformation>[];
+  // Work list of maps to analyze after analyzing the users of a
+  // [TypeInformation]. We know the [tracedType] has been stored in these
+  // maps and we must check how it escapes from these maps.
+  final List<MapTypeInformation> mapsToAnalyze =
+      <MapTypeInformation>[];
 
   final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
 
@@ -81,7 +102,7 @@
   }
 
   void analyze() {
-    // Collect the [TypeInformation] where the container can flow in,
+    // Collect the [TypeInformation] where the list can flow in,
     // as well as the operations done on all these [TypeInformation]s.
     addNewEscapeInformation(tracedType);
     while (!workList.isEmpty) {
@@ -90,8 +111,11 @@
         analyzedElements.add(info.owner);
         info.accept(this);
       });
-      while (!containersToAnalyze.isEmpty) {
-        analyzeStoredIntoContainer(containersToAnalyze.removeLast());
+      while (!listsToAnalyze.isEmpty) {
+        analyzeStoredIntoList(listsToAnalyze.removeLast());
+      }
+      while (!mapsToAnalyze.isEmpty) {
+        analyzeStoredIntoMap(mapsToAnalyze.removeLast());
       }
       if (!continueAnalyzing) break;
       if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
@@ -121,10 +145,21 @@
     addNewEscapeInformation(info);
   }
 
-  visitListTypeInformation(ListTypeInformation info) {
-    containersToAnalyze.add(info);
+  void visitKeyInMapTypeInformation(KeyInMapTypeInformation info) {
+    addNewEscapeInformation(info);
   }
 
+  void visitValueInMapTypeInformation(ValueInMapTypeInformation info) {
+    addNewEscapeInformation(info);
+  }
+
+  void visitListTypeInformation(ListTypeInformation info) {
+    listsToAnalyze.add(info);
+  }
+
+  void visitMapTypeInformation(MapTypeInformation info) {
+    mapsToAnalyze.add(info);
+  }
   void visitConcreteTypeInformation(ConcreteTypeInformation info) {}
 
   void visitClosureTypeInformation(ClosureTypeInformation info) {}
@@ -139,19 +174,38 @@
     }
   }
 
-  void analyzeStoredIntoContainer(ListTypeInformation container) {
-    inferrer.analyzeContainer(container);
-    if (container.bailedOut) {
-      bailout('Stored in a container that bailed out');
+  void analyzeStoredIntoList(ListTypeInformation list) {
+    inferrer.analyzeListAndEnqueue(list);
+    if (list.bailedOut) {
+      bailout('Stored in a list that bailed out');
     } else {
-      container.flowsInto.forEach((flow) {
+      list.flowsInto.forEach((flow) {
         flow.users.forEach((user) {
           if (user is !DynamicCallSiteTypeInformation) return;
           if (user.receiver != flow) return;
-          if (returnsElementTypeSet.contains(user.selector)) {
+          if (returnsListElementTypeSet.contains(user.selector)) {
             addNewEscapeInformation(user);
-          } else if (!doesNotEscapeElementSet.contains(user.selector.name)) {
-            bailout('Escape from a container');
+          } else if (!doesNotEscapeListSet.contains(user.selector.name)) {
+            bailout('Escape from a list');
+          }
+        });
+      });
+    }
+  }
+
+  void analyzeStoredIntoMap(MapTypeInformation map) {
+    inferrer.analyzeMapAndEnqueue(map);
+    if (map.bailedOut) {
+      bailout('Stored in a map that bailed out');
+    } else {
+      map.flowsInto.forEach((flow) {
+        flow.users.forEach((user) {
+          if (user is !DynamicCallSiteTypeInformation) return;
+          if (user.receiver != flow) return;
+          if (user.selector.isIndex()) {
+            addNewEscapeInformation(user);
+          } else if (!doesNotEscapeMapSet.contains(user.selector.name)) {
+            bailout('Escape from a map');
           }
         });
       });
@@ -169,20 +223,40 @@
         || (selectorName == 'add' && currentUser == arguments[0]);
   }
 
+  bool isValueAddedToMap(DynamicCallSiteTypeInformation info) {
+    if (info.arguments == null) return false;
+    var receiverType = info.receiver.type;
+    if (!receiverType.isMap) return false;
+    String selectorName = info.selector.name;
+    List<TypeInformation> arguments = info.arguments.positional;
+    return selectorName == '[]=' && currentUser == arguments[1];
+  }
+
   void visitDynamicCallSiteTypeInformation(
       DynamicCallSiteTypeInformation info) {
     if (isAddedToContainer(info)) {
       ContainerTypeMask mask = info.receiver.type;
       if (mask.allocationNode != null) {
-        ListTypeInformation container =
+        ListTypeInformation list =
             inferrer.types.allocatedLists[mask.allocationNode];
-        containersToAnalyze.add(container);
+        listsToAnalyze.add(list);
       } else {
         // The [ContainerTypeMask] is a union of two containers, and
         // we lose track of where these containers have been allocated
         // at this point.
         bailout('Stored in too many containers');
       }
+    } else if (isValueAddedToMap(info)) {
+      MapTypeMask mask = info.receiver.type;
+      if (mask.allocationNode != null) {
+        MapTypeInformation map =
+            inferrer.types.allocatedMaps[mask.allocationNode];
+        mapsToAnalyze.add(map);
+      } else {
+        // The [MapTypeMask] is a union. See comment for
+        // [ContainerTypeMask] above.
+        bailout('Stored in too many maps');
+      }
     }
 
     Iterable<Element> inferredTargetTypes = info.targets.map((element) {
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
index 34c9c02..8137f75 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
@@ -107,7 +107,8 @@
     return new ContainerTypeMask(type, node, enclosing, elementType, length);
   }
 
-  TypeMask allocateMap(TypeMask keys, TypeMask values, TypeMask type) {
+  TypeMask allocateMap(TypeMask type, Node node, Element element,
+                       [TypeMask keys, TypeMask values]) {
     return type;
   }
 
@@ -629,27 +630,35 @@
   }
 
   T visitLiteralMap(LiteralMap node) {
-    NodeList entries = node.entries;
-    T keyType;
-    T valueType;
-    if (entries.isEmpty) {
-      keyType = types.nonNullEmpty();
-      valueType = types.nonNullEmpty();
-    } else {
-      for (LiteralMapEntry entry in entries) {
-        T key = visit(entry.key);
-        keyType = keyType == null
-            ? types.allocatePhi(null, null, key)
-            : types.addPhiInput(null, keyType, key);
+    return inferrer.concreteTypes.putIfAbsent(node, () {
+      NodeList entries = node.entries;
+      T keyType;
+      T valueType;
+      if (entries.isEmpty) {
+        keyType = types.nonNullEmpty();
+        valueType = types.nonNullEmpty();
+      } else {
+        for (LiteralMapEntry entry in entries) {
+          T key = visit(entry.key);
+          keyType = keyType == null
+              ? types.allocatePhi(null, null, key)
+              : types.addPhiInput(null, keyType, key);
 
-        T value = visit(entry.value);
-        valueType = valueType == null
-            ? types.allocatePhi(null, null, value)
-            : types.addPhiInput(null, valueType, value);
+          T value = visit(entry.value);
+          valueType = valueType == null
+              ? types.allocatePhi(null, null, value)
+              : types.addPhiInput(null, valueType, value);
+        }
+        keyType = types.simplifyPhi(null, null, keyType);
+        valueType = types.simplifyPhi(null, null, valueType);
       }
-    }
-    T type = node.isConst() ? types.constMapType : types.mapType;
-    return types.allocateMap(keyType, valueType, type);
+      T type = node.isConst() ? types.constMapType : types.mapType;
+      return types.allocateMap(type,
+                               node,
+                               outermostElement,
+                               keyType,
+                               valueType);
+    });
   }
 
   bool isThisOrSuper(Node node) => node.isThis() || node.isSuper();
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
index b568d03..80d5bb6 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
@@ -9,7 +9,8 @@
 import '../elements/elements.dart';
 import '../tree/tree.dart' show LiteralList, Node;
 import '../ir/ir_nodes.dart' show IrNode;
-import '../types/types.dart' show TypeMask, ContainerTypeMask, TypesInferrer;
+import '../types/types.dart'
+  show TypeMask, ContainerTypeMask, MapTypeMask, TypesInferrer;
 import '../universe/universe.dart' show Selector, TypedSelector, SideEffects;
 import '../dart2jslib.dart' show Compiler, TreeElementMapping;
 import 'inferrer_visitor.dart' show TypeSystem, ArgumentsTypes;
@@ -17,12 +18,13 @@
 import '../util/util.dart' show Spannable, Setlet;
 import 'simple_types_inferrer.dart';
 import 'ir_type_inferrer.dart';
-import '../dart2jslib.dart' show invariant, Constant;
+import '../dart2jslib.dart' show invariant, Constant, FunctionConstant;
 
 part 'type_graph_nodes.dart';
 part 'closure_tracer.dart';
 part 'list_tracer.dart';
 part 'node_tracer.dart';
+part 'map_tracer.dart';
 
 bool _VERBOSE = false;
 
@@ -30,7 +32,7 @@
  * A set of selector names that [List] implements, that we know return
  * their element type.
  */
-Set<Selector> returnsElementTypeSet = new Set<Selector>.from(
+Set<Selector> returnsListElementTypeSet = new Set<Selector>.from(
   <Selector>[
     new Selector.getter('first', null),
     new Selector.getter('last', null),
@@ -42,10 +44,16 @@
     new Selector.call('removeLast', null, 0)
   ]);
 
-bool returnsElementType(Selector selector) {
+bool returnsListElementType(Selector selector) {
   return (selector.mask != null)
          && selector.mask.isContainer
-         && returnsElementTypeSet.contains(selector.asUntyped);
+         && returnsListElementTypeSet.contains(selector.asUntyped);
+}
+
+bool returnsMapValueType(Selector selector) {
+  return (selector.mask != null)
+         && selector.mask.isMap
+         && selector.isIndex();
 }
 
 class TypeInformationSystem extends TypeSystem<TypeInformation> {
@@ -59,6 +67,10 @@
   final Map<Node, TypeInformation> allocatedLists =
       new Map<Node, TypeInformation>();
 
+  /// [MapTypeInformation] for allocated Maps.
+  final Map<Node, TypeInformation> allocatedMaps =
+      new Map<Node, TypeInformation>();
+
   /// Closures found during the analysis.
   final Set<TypeInformation> allocatedClosures = new Set<TypeInformation>();
 
@@ -311,12 +323,35 @@
     return result;
   }
 
-  TypeInformation allocateMap(TypeInformation keyType,
-                              TypeInformation valueType,
-                              ConcreteTypeInformation type) {
+  TypeInformation allocateMap(ConcreteTypeInformation type,
+                              Node node,
+                              Element element,
+                              [TypeInformation keyType,
+                              TypeInformation valueType]) {
+    bool isFixed = (type.type == compiler.typesTask.constMapType);
+
+    // transform the key and value into inferrable type informations
+    KeyInMapTypeInformation inferredKeyType =
+        new KeyInMapTypeInformation(keyType);
+    ValueInMapTypeInformation inferredValueType =
+        new ValueInMapTypeInformation(valueType);
+    if (isFixed) {
+      inferredValueType.inferred = inferredKeyType.inferred = true;
+    }
+    MapTypeMask mask = new MapTypeMask(type.type,
+                                       node,
+                                       element,
+                                       isFixed ? keyType.type
+                                               : dynamicType.type,
+                                       isFixed ? valueType.type
+                                               : dynamicType.type);
+
     MapTypeInformation map =
-        new MapTypeInformation(keyType, valueType, type.type);
-    allocatedTypes.add(map);
+      new MapTypeInformation(inferredKeyType, inferredValueType, mask);
+
+    allocatedTypes.add(inferredKeyType);
+    allocatedTypes.add(inferredValueType);
+    allocatedMaps[node] = map;
     return map;
   }
 
@@ -441,12 +476,11 @@
   TypeGraphInferrerEngine(Compiler compiler, this.mainElement)
         : super(compiler, new TypeInformationSystem(compiler));
 
-  void analyzeContainer(ListTypeInformation info) {
+  void analyzeListAndEnqueue(ListTypeInformation info) {
     if (info.analyzed) return;
     info.analyzed = true;
     ListTracerVisitor tracer = new ListTracerVisitor(info, this);
-    List<TypeInformation> newAssignments = tracer.run();
-    if (newAssignments == null) {
+    if (!tracer.run()) {
       return;
     }
     info.bailedOut = false;
@@ -455,7 +489,26 @@
     if (info.originalContainerType.forwardTo == fixedListType) {
       info.checksGrowable = tracer.callsGrowableMethod;
     }
-    newAssignments.forEach(info.elementType.addAssignment);
+    tracer.assignments.forEach(info.elementType.addAssignment);
+    // Enqueue the list for later refinement
+    workQueue.add(info);
+    workQueue.add(info.elementType);
+  }
+
+  void analyzeMapAndEnqueue(MapTypeInformation info) {
+    if (info.analyzed) return;
+    info.analyzed = true;
+    MapTracerVisitor tracer = new MapTracerVisitor(info, this);
+    if (!tracer.run()) return;
+    info.bailedOut = false;
+    info.keyType.inferred = true;
+    tracer.keyAssignments.forEach(info.keyType.addAssignment);
+    workQueue.add(info.keyType);
+    info.valueType.inferred = true;
+    tracer.valueAssignments.forEach(info.valueType.addAssignment);
+    // Enqueue the map for later refinement
+    workQueue.add(info.valueType);
+    workQueue.add(info);
   }
 
   void runOverAllElements() {
@@ -480,10 +533,13 @@
     // Try to infer element types of lists.
     types.allocatedLists.values.forEach((ListTypeInformation info) {
       if (info.elementType.inferred) return;
-      analyzeContainer(info);
-      if (info.bailedOut) return;
-      workQueue.add(info);
-      workQueue.add(info.elementType);
+      analyzeListAndEnqueue(info);
+    });
+
+    // Try to infer the key and value types for maps.
+    types.allocatedMaps.values.forEach((MapTypeInformation info) {
+      if (info.keyType.inferred && info.valueType.inferred) return;
+      analyzeMapAndEnqueue(info);
     });
 
     types.allocatedClosures.forEach((info) {
@@ -498,8 +554,8 @@
       });
     });
 
-    // Reset all nodes that use lists that have been inferred, as well
-    // as nodes that use elements fetched from these lists. The
+    // Reset all nodes that use lists/maps that have been inferred, as well
+    // as nodes that use elements fetched from these lists/maps. The
     // workset for a new run of the analysis will be these nodes.
     Set<TypeInformation> seenTypes = new Set<TypeInformation>();
     while (!workQueue.isEmpty) {
@@ -519,6 +575,11 @@
               'for ${info.originalContainerType.allocationNode} '
               'at ${info.originalContainerType.allocationElement}');
       });
+      types.allocatedMaps.values.forEach((MapTypeInformation info) {
+        print('${info.type} '
+              'for ${(info.type as MapTypeMask).allocationNode} '
+              'at ${(info.type as MapTypeMask).allocationElement}');
+      });
     }
 
     compiler.log('Inferred $overallRefineCount types.');
@@ -555,7 +616,12 @@
             Constant value =
                 compiler.constantHandler.getConstantForVariable(element);
             if (value != null) {
-              type = types.getConcreteTypeFor(value.computeMask(compiler));
+              if (value.isFunction()) {
+                FunctionConstant functionConstant = value;
+                type = types.allocateClosure(node, functionConstant.element);
+              } else {
+                type = types.getConcreteTypeFor(value.computeMask(compiler));
+              }
             }
           }
           recordType(element, type);
@@ -975,11 +1041,17 @@
     if (selector.isSetter() || selector.isIndexSet()) {
       return compiler.typesTask.dynamicType;
     }
-    if (returnsElementType(selector)) {
+    if (returnsListElementType(selector)) {
       ContainerTypeMask mask = selector.mask;
       TypeMask elementType = mask.elementType;
       return elementType == null ? compiler.typesTask.dynamicType : elementType;
     }
+    if (returnsMapValueType(selector)) {
+      MapTypeMask mask = selector.mask;
+      TypeMask valueType = mask.valueType;
+      return valueType == null ? compiler.typesTask.dynamicType
+                               : valueType.nullable();
+    }
 
     TypeMask result = const TypeMask.nonNullEmpty();
     Iterable<Element> elements = compiler.world.allFunctions.filter(selector);
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
index bd34d0c..fddc6fc 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
@@ -665,9 +665,12 @@
         return const TypeMask.nonNullEmpty();
       }
 
-      if (returnsElementType(typedSelector)) {
+      if (returnsListElementType(typedSelector)) {
         ContainerTypeMask mask = receiver.type;
         return mask.elementType;
+      } else if (returnsMapValueType(typedSelector)) {
+        MapTypeMask mask = receiver.type;
+        return mask.valueType.nullable();
       } else {
         TypeInformation info =
             handleIntrisifiedSelector(typedSelector, inferrer);
@@ -866,6 +869,32 @@
 }
 
 /**
+ * An [InferredTypeInformation] is a [TypeInformation] that
+ * defaults to the dynamic type until it is marked as beeing
+ * inferred, at which point it computes its type based on
+ * its assignments.
+ */
+abstract class InferredTypeInformation extends TypeInformation {
+  /** Whether the element type in that container has been inferred. */
+  bool inferred = false;
+
+  InferredTypeInformation(parentType) {
+    if (parentType != null) addAssignment(parentType);
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    if (!inferred) {
+      return inferrer.types.dynamicType.type;
+    }
+    return inferrer.types.computeTypeMask(assignments);
+  }
+
+  bool hasStableType(TypeGraphInferrerEngine inferrer) {
+    return inferred && super.hasStableType(inferrer);
+  }
+}
+
+/**
  * A [ListTypeInformation] is a [TypeInformation] created
  * for each `List` instantiations.
  */
@@ -931,30 +960,14 @@
  * An [ElementInContainerTypeInformation] holds the common type of the
  * elements in a [ListTypeInformation].
  */
-class ElementInContainerTypeInformation extends TypeInformation {
-  /** Whether the element type in that container has been inferred. */
-  bool inferred = false;
-
-  ElementInContainerTypeInformation(elementType) {
-    if (elementType != null) addAssignment(elementType);
-  }
-
-  TypeMask refine(TypeGraphInferrerEngine inferrer) {
-    if (!inferred) {
-      return inferrer.types.dynamicType.type;
-    }
-    return inferrer.types.computeTypeMask(assignments);
-  }
+class ElementInContainerTypeInformation extends InferredTypeInformation {
+  ElementInContainerTypeInformation(elementType) : super(elementType);
 
   String toString() => 'Element in container $type';
 
   accept(TypeInformationVisitor visitor) {
     return visitor.visitElementInContainerTypeInformation(this);
   }
-
-  bool hasStableType(TypeGraphInferrerEngine inferrer) {
-    return inferred && super.hasStableType(inferrer);
-  }
 }
 
 /**
@@ -962,9 +975,17 @@
  * for maps.
  */
 class MapTypeInformation extends TypeInformation {
-  final TypeInformation keyType;
-  final TypeInformation valueType;
-  final TypeMask initialType;
+  final KeyInMapTypeInformation keyType;
+  final ValueInMapTypeInformation valueType;
+  final MapTypeMask initialType;
+
+  // The set of [TypeInformation] where values from the traced map could
+  // flow in.
+  final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
+
+  // Set to false once analysis has succeeded.
+  bool bailedOut = true;
+  bool analyzed = false;
 
   MapTypeInformation(this.keyType, this.valueType, this.initialType) {
     keyType.addUser(this);
@@ -977,10 +998,63 @@
   }
 
   TypeMask refine(TypeGraphInferrerEngine inferrer) {
-    return initialType;
+    var mask = type;
+    if (!mask.isMap
+        || mask.keyType != keyType.type
+        || mask.valueType != valueType.type) {
+      return new MapTypeMask(initialType.forwardTo,
+                             initialType.allocationNode,
+                             initialType.allocationElement,
+                             keyType.type,
+                             valueType.type);
+    }
+
+    return mask;
   }
 
-  String toString() => 'Map $type';
+  bool hasStableType(TypeGraphInferrerEngine inferrer) {
+    return keyType.isStable
+           && valueType.isStable
+           && super.hasStableType(inferrer);
+  }
+
+  String toString() => 'Map $type (K:$keyType, V:$valueType)';
+}
+
+/**
+ * A [KeyInMapTypeInformation] holds the common type
+ * for the keys in a [MapTypeInformation]
+ */
+class KeyInMapTypeInformation extends InferredTypeInformation {
+  KeyInMapTypeInformation(TypeInformation keyType) : super(keyType);
+
+  accept(TypeInformationVisitor visitor) {
+    return visitor.visitKeyInMapTypeInformation(this);
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    return super.refine(inferrer);
+  }
+
+  String toString() => 'Key in Map $type';
+}
+
+/**
+ * A [ValueInMapTypeInformation] holds the common type
+ * for the values in a [MapTypeInformation]
+ */
+class ValueInMapTypeInformation extends InferredTypeInformation {
+  ValueInMapTypeInformation(TypeInformation valueType) : super(valueType);
+
+  accept(TypeInformationVisitor visitor) {
+    return visitor.visitValueInMapTypeInformation(this);
+  }
+
+  TypeMask refine(TypeGraphInferrerEngine inferrer) {
+    return super.refine(inferrer);
+  }
+
+  String toString() => 'Value in Map $type';
 }
 
 /**
@@ -1031,6 +1105,8 @@
   T visitPhiElementTypeInformation(PhiElementTypeInformation info);
   T visitElementInContainerTypeInformation(
       ElementInContainerTypeInformation info);
+  T visitKeyInMapTypeInformation(KeyInMapTypeInformation info);
+  T visitValueInMapTypeInformation(ValueInMapTypeInformation info);
   T visitListTypeInformation(ListTypeInformation info);
   T visitMapTypeInformation(MapTypeInformation info);
   T visitConcreteTypeInformation(ConcreteTypeInformation info);
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 35abf1c..36ddfa5 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -1738,10 +1738,12 @@
   }
 
   bool couldBeTypedArray(TypeMask mask) {
-    TypeMask indexing = new TypeMask.subtype(jsIndexingBehaviorInterface);
-    // Checking if [mask] contains [indexing] means that we want to
-    // know if [mask] is not a more specific type than [indexing].
-    return isTypedArray(mask) || mask.containsMask(indexing, compiler);
+    bool intersects(TypeMask type1, TypeMask type2) =>
+        !type1.intersection(type2, compiler).isEmpty;
+
+    return compiler.typedDataClass != null
+        && intersects(mask, new TypeMask.subtype(compiler.typedDataClass))
+        && intersects(mask, new TypeMask.subtype(jsIndexingBehaviorInterface));
   }
 
   /// Returns all static fields that are referenced through [targetsUsed].
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 93241b7..2f81f2d 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -1381,16 +1381,15 @@
         emitFinishClassesInvocationIfNecessary(mainBuffer);
         classesCollector = oldClassesCollector;
       }
-
-      typeTestEmitter.emitRuntimeTypeSupport(mainBuffer);
+      OutputUnit mainOutputUnit = compiler.deferredLoadTask.mainOutputUnit;
+      typeTestEmitter.emitRuntimeTypeSupport(mainBuffer, mainOutputUnit);
       interceptorEmitter.emitGetInterceptorMethods(mainBuffer);
       interceptorEmitter.emitOneShotInterceptors(mainBuffer);
       // Constants in checked mode call into RTI code to set type information
       // which may need getInterceptor (and one-shot interceptor) methods, so
       // we have to make sure that [emitGetInterceptorMethods] and
       // [emitOneShotInterceptors] have been called.
-      emitCompileTimeConstants(
-          mainBuffer, compiler.deferredLoadTask.mainOutputUnit);
+      emitCompileTimeConstants(mainBuffer, mainOutputUnit);
 
       // We write a javascript mapping from DeferredLibrary elements
       // (really their String argument) to the js hunk to load.
@@ -1569,6 +1568,8 @@
 
       classesCollector = oldClassesCollector;
 
+      typeTestEmitter.emitRuntimeTypeSupport(buffer, outputUnit);
+
       emitCompileTimeConstants(buffer, outputUnit);
 
       String code = buffer.getText();
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
index 9070243..2881d91 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/js_emitter.dart
@@ -4,8 +4,6 @@
 
 library dart2js.js_emitter;
 
-import 'dart:collection' show Queue;
-
 import '../common.dart';
 
 import '../js/js.dart' as jsAst;
@@ -59,8 +57,6 @@
 import '../util/uri_extras.dart' show
     relativize;
 
-import '../dump_info.dart' as dumpInfo;
-
 import '../deferred_load.dart' show
     OutputUnit;
 
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
index 8733590..87a5036 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
@@ -276,13 +276,18 @@
     }
   }
 
-  void emitRuntimeTypeSupport(CodeBuffer buffer) {
+  void emitRuntimeTypeSupport(CodeBuffer buffer, OutputUnit outputUnit) {
     task.addComment('Runtime type support', buffer);
     RuntimeTypes rti = backend.rti;
     TypeChecks typeChecks = rti.requiredChecks;
 
     // Add checks to the constructors of instantiated classes.
+    // TODO(sigurdm): We should avoid running through this list for each
+    // output unit.
     for (ClassElement cls in typeChecks) {
+      OutputUnit destination =
+          compiler.deferredLoadTask.outputUnitForElement(cls);
+      if (destination != outputUnit) continue;
       // TODO(9556).  The properties added to 'holder' should be generated
       // directly as properties of the class object, not added later.
       String holder = namer.isolateAccess(backend.getImplementationClass(cls));
@@ -306,12 +311,20 @@
       buffer.write(jsAst.prettyPrint(encoding, compiler));
       buffer.add('$N');
     }
+    if (outputUnit == compiler.deferredLoadTask.mainOutputUnit) {
+      // TODO(sigurdm): These should also be possibly deferred.
+      // They should be handled similarly to constants.
+      // They have 3 dependencies:
+      // 1. The libraries containing the check.
+      // 2. The typedef defining it.
+      // 3. The types involved in the typedef.
+      // TODO(sigurdm): Actually these seems to never be used. Remove them.
+      checkedNonGenericFunctionTypes.forEach(addSignature);
+      checkedGenericFunctionTypes.forEach((_, Set<FunctionType> functionTypes) {
+        functionTypes.forEach(addSignature);
+      });
+    }
 
-    checkedNonGenericFunctionTypes.forEach(addSignature);
-
-    checkedGenericFunctionTypes.forEach((_, Set<FunctionType> functionTypes) {
-      functionTypes.forEach(addSignature);
-    });
   }
 
   /**
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart b/sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart
new file mode 100644
index 0000000..c1231a8
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2012, 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.

+

+library dart2js.source_mirrors.analyze;

+

+import 'dart:async';

+

+import 'source_mirrors.dart';

+import 'dart2js_mirrors.dart' show Dart2JsMirrorSystem;

+import '../../compiler.dart' as api;

+import '../apiimpl.dart' as apiimpl;

+import '../dart2jslib.dart' show Compiler;

+

+//------------------------------------------------------------------------------

+// Analysis entry point.

+//------------------------------------------------------------------------------

+

+/**

+ * Analyzes set of libraries and provides a mirror system which can be used for

+ * static inspection of the source code.

+ */

+// TODO(johnniwinther): Move this to [compiler/compiler.dart].

+Future<MirrorSystem> analyze(List<Uri> libraries,

+                             Uri libraryRoot,

+                             Uri packageRoot,

+                             api.CompilerInputProvider inputProvider,

+                             api.DiagnosticHandler diagnosticHandler,

+                             [List<String> options = const <String>[]]) {

+  if (!libraryRoot.path.endsWith("/")) {

+    throw new ArgumentError("libraryRoot must end with a /");

+  }

+  if (packageRoot != null && !packageRoot.path.endsWith("/")) {

+    throw new ArgumentError("packageRoot must end with a /");

+  }

+  options = new List<String>.from(options);

+  options.add('--analyze-only');

+  options.add('--analyze-signatures-only');

+  options.add('--analyze-all');

+  options.add('--categories=Client,Server');

+

+  bool compilationFailed = false;

+  void internalDiagnosticHandler(Uri uri, int begin, int end,

+                                 String message, api.Diagnostic kind) {

+    if (kind == api.Diagnostic.ERROR ||

+        kind == api.Diagnostic.CRASH) {

+      compilationFailed = true;

+    }

+    diagnosticHandler(uri, begin, end, message, kind);

+  }

+

+  Compiler compiler = new apiimpl.Compiler(inputProvider,

+                                           null,

+                                           internalDiagnosticHandler,

+                                           libraryRoot, packageRoot,

+                                           options,

+                                           const {});

+  compiler.librariesToAnalyzeWhenRun = libraries;

+  return compiler.run(null).then((bool success) {

+    if (success && !compilationFailed) {

+      return new Dart2JsMirrorSystem(compiler);

+    } else {

+      throw new StateError('Failed to create mirror system.');

+    }

+  });

+}

diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_instance_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_instance_mirrors.dart
new file mode 100644
index 0000000..40a5d3f
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_instance_mirrors.dart
@@ -0,0 +1,285 @@
+// 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.mirrors;

+

+abstract class ObjectMirrorMixin implements ObjectMirror {

+  InstanceMirror getField(Symbol fieldName) {

+    throw new UnsupportedError('ObjectMirror.getField unsupported.');

+  }

+

+  InstanceMirror setField(Symbol fieldName, Object value) {

+    throw new UnsupportedError('ObjectMirror.setField unsupported.');

+  }

+

+  InstanceMirror invoke(Symbol memberName,

+                        List positionalArguments,

+                        [Map<Symbol, dynamic> namedArguments]) {

+    throw new UnsupportedError('ObjectMirror.invoke unsupported.');

+  }

+}

+

+abstract class InstanceMirrorMixin implements InstanceMirror {

+

+  bool get hasReflectee => false;

+

+  get reflectee {

+    throw new UnsupportedError('InstanceMirror.reflectee unsupported.');

+  }

+

+  Function operator [](Symbol name) {

+    throw new UnsupportedError('InstanceMirror.operator [] unsupported.');

+  }

+

+  delegate(Invocation invocation) {

+    throw new UnsupportedError('InstanceMirror.delegate unsupported');

+  }

+}

+

+InstanceMirror _convertConstantToInstanceMirror(

+    Dart2JsMirrorSystem mirrorSystem, Constant constant) {

+  if (constant is BoolConstant) {

+    return new Dart2JsBoolConstantMirror(mirrorSystem, constant);

+  } else if (constant is NumConstant) {

+    return new Dart2JsNumConstantMirror(mirrorSystem, constant);

+  } else if (constant is StringConstant) {

+    return new Dart2JsStringConstantMirror(mirrorSystem, constant);

+  } else if (constant is ListConstant) {

+    return new Dart2JsListConstantMirror(mirrorSystem, constant);

+  } else if (constant is MapConstant) {

+    return new Dart2JsMapConstantMirror(mirrorSystem, constant);

+  } else if (constant is TypeConstant) {

+    return new Dart2JsTypeConstantMirror(mirrorSystem, constant);

+  } else if (constant is FunctionConstant) {

+    return new Dart2JsConstantMirror(mirrorSystem, constant);

+  } else if (constant is NullConstant) {

+    return new Dart2JsNullConstantMirror(mirrorSystem, constant);

+  } else if (constant is ConstructedConstant) {

+    return new Dart2JsConstructedConstantMirror(mirrorSystem, constant);

+  }

+  mirrorSystem.compiler.internalError("Unexpected constant $constant");

+}

+

+

+////////////////////////////////////////////////////////////////////////////////

+// Mirrors on constant values used for metadata.

+////////////////////////////////////////////////////////////////////////////////

+

+class Dart2JsConstantMirror extends Object

+    with ObjectMirrorMixin, InstanceMirrorMixin

+    implements InstanceMirror {

+  final Dart2JsMirrorSystem mirrorSystem;

+  final Constant _constant;

+

+  Dart2JsConstantMirror(this.mirrorSystem, this._constant);

+

+  // TODO(johnniwinther): Improve the quality of this method.

+  String toString() => '$_constant';

+

+  ClassMirror get type {

+    return mirrorSystem._getTypeDeclarationMirror(

+        _constant.computeType(mirrorSystem.compiler).element);

+  }

+

+  int get hashCode => 13 * _constant.hashCode;

+

+  bool operator ==(var other) {

+    if (other is! Dart2JsConstantMirror) return false;

+    return _constant == other._constant;

+  }

+}

+

+class Dart2JsNullConstantMirror extends Dart2JsConstantMirror {

+  Dart2JsNullConstantMirror(Dart2JsMirrorSystem mirrorSystem,

+                            NullConstant constant)

+      : super(mirrorSystem, constant);

+

+  NullConstant get _constant => super._constant;

+

+  bool get hasReflectee => true;

+

+  get reflectee => null;

+}

+

+class Dart2JsBoolConstantMirror extends Dart2JsConstantMirror {

+  Dart2JsBoolConstantMirror(Dart2JsMirrorSystem mirrorSystem,

+                            BoolConstant constant)

+      : super(mirrorSystem, constant);

+

+  Dart2JsBoolConstantMirror.fromBool(Dart2JsMirrorSystem mirrorSystem,

+                                     bool value)

+      : super(mirrorSystem, value ? new TrueConstant() : new FalseConstant());

+

+  BoolConstant get _constant => super._constant;

+

+  bool get hasReflectee => true;

+

+  get reflectee => _constant is TrueConstant;

+}

+

+class Dart2JsStringConstantMirror extends Dart2JsConstantMirror {

+  Dart2JsStringConstantMirror(Dart2JsMirrorSystem mirrorSystem,

+                              StringConstant constant)

+      : super(mirrorSystem, constant);

+

+  Dart2JsStringConstantMirror.fromString(Dart2JsMirrorSystem mirrorSystem,

+                                         String text)

+      : super(mirrorSystem, new StringConstant(new DartString.literal(text)));

+

+  StringConstant get _constant => super._constant;

+

+  bool get hasReflectee => true;

+

+  get reflectee => _constant.value.slowToString();

+}

+

+class Dart2JsNumConstantMirror extends Dart2JsConstantMirror {

+  Dart2JsNumConstantMirror(Dart2JsMirrorSystem mirrorSystem,

+                           NumConstant constant)

+      : super(mirrorSystem, constant);

+

+  NumConstant get _constant => super._constant;

+

+  bool get hasReflectee => true;

+

+  get reflectee => _constant.value;

+}

+

+class Dart2JsListConstantMirror extends Dart2JsConstantMirror

+    implements ListInstanceMirror {

+  Dart2JsListConstantMirror(Dart2JsMirrorSystem mirrorSystem,

+                            ListConstant constant)

+      : super(mirrorSystem, constant);

+

+  ListConstant get _constant => super._constant;

+

+  int get length => _constant.length;

+

+  InstanceMirror getElement(int index) {

+    if (index < 0) throw new RangeError('Negative index');

+    if (index >= _constant.length) throw new RangeError('Index out of bounds');

+    return _convertConstantToInstanceMirror(mirrorSystem,

+                                            _constant.entries[index]);

+  }

+}

+

+class Dart2JsMapConstantMirror extends Dart2JsConstantMirror

+    implements MapInstanceMirror {

+  List<String> _listCache;

+

+  Dart2JsMapConstantMirror(Dart2JsMirrorSystem mirrorSystem,

+                           MapConstant constant)

+      : super(mirrorSystem, constant);

+

+  MapConstant get _constant => super._constant;

+

+  List<String> get _list {

+    if (_listCache == null) {

+      _listCache = new List<String>(_constant.keys.entries.length);

+      int index = 0;

+      for (StringConstant keyConstant in _constant.keys.entries) {

+        _listCache[index] = keyConstant.value.slowToString();

+        index++;

+      }

+      _listCache = new UnmodifiableListView<String>(_listCache);

+    }

+    return _listCache;

+  }

+

+  int get length => _constant.length;

+

+  Iterable<String> get keys {

+    return _list;

+  }

+

+  InstanceMirror getValue(String key) {

+    int index = _list.indexOf(key);

+    if (index == -1) return null;

+    return _convertConstantToInstanceMirror(mirrorSystem,

+                                            _constant.values[index]);

+  }

+}

+

+class Dart2JsTypeConstantMirror extends Dart2JsConstantMirror

+    implements TypeInstanceMirror {

+

+  Dart2JsTypeConstantMirror(Dart2JsMirrorSystem mirrorSystem,

+                            TypeConstant constant)

+      : super(mirrorSystem, constant);

+

+  TypeConstant get _constant => super._constant;

+

+  TypeMirror get representedType =>

+      mirrorSystem._convertTypeToTypeMirror(_constant.representedType);

+}

+

+class Dart2JsConstructedConstantMirror extends Dart2JsConstantMirror {

+  Map<String,Constant> _fieldMapCache;

+

+  Dart2JsConstructedConstantMirror(Dart2JsMirrorSystem mirrorSystem,

+                                   ConstructedConstant constant)

+      : super(mirrorSystem, constant);

+

+  ConstructedConstant get _constant => super._constant;

+

+  Map<String,Constant> get _fieldMap {

+    if (_fieldMapCache == null) {

+      _fieldMapCache = new Map<String,Constant>();

+      if (identical(_constant.type.element.kind, ElementKind.CLASS)) {

+        var index = 0;

+        ClassElement element = _constant.type.element;

+        element.forEachInstanceField((_, Element field) {

+          String fieldName = field.name;

+          _fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]);

+          index++;

+        }, includeSuperAndInjectedMembers: true);

+      }

+    }

+    return _fieldMapCache;

+  }

+

+  InstanceMirror getField(Symbol fieldName) {

+    Constant fieldConstant = _fieldMap[MirrorSystem.getName(fieldName)];

+    if (fieldConstant != null) {

+      return _convertConstantToInstanceMirror(mirrorSystem, fieldConstant);

+    }

+    return super.getField(fieldName);

+  }

+}

+

+class Dart2JsCommentInstanceMirror extends Object

+  with ObjectMirrorMixin, InstanceMirrorMixin

+  implements CommentInstanceMirror {

+  final Dart2JsMirrorSystem mirrorSystem;

+  final String text;

+  String _trimmedText;

+

+  Dart2JsCommentInstanceMirror(this.mirrorSystem, this.text);

+

+  ClassMirror get type {

+    return mirrorSystem._getTypeDeclarationMirror(

+        mirrorSystem.compiler.documentClass);

+  }

+

+  bool get isDocComment => text.startsWith('/**') || text.startsWith('///');

+

+  String get trimmedText {

+    if (_trimmedText == null) {

+      _trimmedText = stripComment(text);

+    }

+    return _trimmedText;

+  }

+

+  InstanceMirror getField(Symbol fieldName) {

+    if (fieldName == #isDocComment) {

+      return new Dart2JsBoolConstantMirror.fromBool(mirrorSystem, isDocComment);

+    } else if (fieldName == #text) {

+      return new Dart2JsStringConstantMirror.fromString(mirrorSystem, text);

+    } else if (fieldName == #trimmedText) {

+      return new Dart2JsStringConstantMirror.fromString(mirrorSystem,

+                                                        trimmedText);

+    }

+    super.getField(fieldName);

+  }

+}

diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_library_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_library_mirror.dart
new file mode 100644
index 0000000..9a5e58d
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_library_mirror.dart
@@ -0,0 +1,234 @@
+// 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.mirrors;

+

+

+class Dart2JsLibraryMirror

+    extends Dart2JsElementMirror

+    with ObjectMirrorMixin, ContainerMixin

+    implements LibrarySourceMirror {

+  List<LibraryDependencyMirror> _libraryDependencies;

+

+  Dart2JsLibraryMirror(Dart2JsMirrorSystem system, LibraryElement library)

+      : super(system, library);

+

+  Function operator [](Symbol name) {

+    throw new UnsupportedError('LibraryMirror.operator [] unsupported.');

+  }

+

+  LibraryElement get _element => super._element;

+

+  Uri get uri => _element.canonicalUri;

+

+  DeclarationMirror get owner => null;

+

+  bool get isPrivate => false;

+

+  LibraryMirror library() => this;

+

+  /**

+   * Returns the library name (for libraries with a library tag) or the script

+   * file name (for scripts without a library tag). The latter case is used to

+   * provide a 'library name' for scripts, to use for instance in dartdoc.

+   */

+  String get _simpleNameString {

+    if (_element.libraryTag != null) {

+      return _element.libraryTag.name.toString();

+    } else {

+      // Use the file name as script name.

+      String path = _element.canonicalUri.path;

+      return path.substring(path.lastIndexOf('/') + 1);

+    }

+  }

+

+  Symbol get qualifiedName => simpleName;

+

+  void _forEachElement(f(Element element)) => _element.forEachLocalMember(f);

+

+  Iterable<Dart2JsDeclarationMirror> _getDeclarationMirrors(Element element) {

+    if (element.isClass() || element.isTypedef()) {

+      return [mirrorSystem._getTypeDeclarationMirror(element)];

+    } else {

+      return super._getDeclarationMirrors(element);

+    }

+  }

+

+  Map<Symbol, MethodMirror> get topLevelMembers => null;

+

+  /**

+   * Computes the first token of this library using the first library tag as

+   * indicator.

+   */

+  Token getBeginToken() {

+    if (_element.libraryTag != null) {

+      return _element.libraryTag.getBeginToken();

+    } else if (!_element.tags.isEmpty) {

+      return _element.tags.reverse().head.getBeginToken();

+    }

+    return null;

+  }

+

+  /**

+   * Computes the first token of this library using the last library tag as

+   * indicator.

+   */

+  Token getEndToken() {

+    if (!_element.tags.isEmpty) {

+      return _element.tags.head.getEndToken();

+    }

+    return null;

+  }

+

+  void _ensureLibraryDependenciesAnalyzed() {

+    if (_libraryDependencies == null) {

+      _libraryDependencies = <LibraryDependencyMirror>[];

+      for (LibraryTag node in _element.tags.reverse()) {

+        LibraryDependency libraryDependency = node.asLibraryDependency();

+        if (libraryDependency != null) {

+          LibraryElement targetLibraryElement =

+              _element.getLibraryFromTag(libraryDependency);

+          assert(targetLibraryElement != null);

+          LibraryMirror targetLibrary =

+              mirrorSystem._getLibrary(targetLibraryElement);

+          _libraryDependencies.add(new Dart2JsLibraryDependencyMirror(

+              libraryDependency, this, targetLibrary));

+        }

+      }

+    }

+  }

+

+  List<LibraryDependencyMirror> get libraryDependencies {

+    _ensureLibraryDependenciesAnalyzed();

+    return _libraryDependencies;

+  }

+}

+

+class Dart2JsLibraryDependencyMirror implements LibraryDependencyMirror {

+  final LibraryDependency _node;

+  final Dart2JsLibraryMirror _sourceLibrary;

+  final Dart2JsLibraryMirror _targetLibrary;

+  List<CombinatorMirror> _combinators;

+

+  Dart2JsLibraryDependencyMirror(this._node,

+                                 this._sourceLibrary,

+                                 this._targetLibrary);

+

+  SourceLocation get location {

+    return new Dart2JsSourceLocation(

+      _sourceLibrary._element.entryCompilationUnit.script,

+      _sourceLibrary.mirrorSystem.compiler.spanFromNode(_node));

+  }

+

+  List<CombinatorMirror> get combinators {

+    if (_combinators == null) {

+      _combinators = <CombinatorMirror>[];

+      if (_node.combinators != null) {

+        for (Combinator combinator in _node.combinators.nodes) {

+          List<String> identifiers = <String>[];

+          for (Identifier identifier in combinator.identifiers.nodes) {

+            identifiers.add(identifier.source);

+          }

+          _combinators.add(new Dart2JsCombinatorMirror(

+              identifiers, isShow: combinator.isShow));

+        }

+      }

+    }

+    return _combinators;

+  }

+

+  LibraryMirror get sourceLibrary => _sourceLibrary;

+

+  LibraryMirror get targetLibrary => _targetLibrary;

+

+  String get prefix {

+    Import import = _node.asImport();

+    if (import != null && import.prefix != null) {

+      return import.prefix.source;

+    }

+    return null;

+  }

+

+  bool get isImport => _node.asImport() != null;

+

+  bool get isExport => _node.asExport() != null;

+}

+

+class Dart2JsCombinatorMirror implements CombinatorMirror {

+  final List<String> identifiers;

+  final bool isShow;

+

+  Dart2JsCombinatorMirror(this.identifiers, {bool isShow: true})

+      : this.isShow = isShow;

+

+  bool get isHide => !isShow;

+}

+

+class Dart2JsSourceLocation implements SourceLocation {

+  final Script _script;

+  final SourceSpan _span;

+  int _line;

+  int _column;

+

+  Dart2JsSourceLocation(this._script, this._span);

+

+  int _computeLine() {

+    var sourceFile = _script.file;

+    if (sourceFile != null) {

+      return sourceFile.getLine(offset) + 1;

+    }

+    var index = 0;

+    var lineNumber = 0;

+    while (index <= offset && index < sourceText.length) {

+      index = sourceText.indexOf('\n', index) + 1;

+      if (index <= 0) break;

+      lineNumber++;

+    }

+    return lineNumber;

+  }

+

+  int get line {

+    if (_line == null) {

+      _line = _computeLine();

+    }

+    return _line;

+  }

+

+  int _computeColumn() {

+    if (length == 0) return 0;

+

+    var sourceFile = _script.file;

+    if (sourceFile != null) {

+      return sourceFile.getColumn(sourceFile.getLine(offset), offset) + 1;

+    }

+    int index = offset - 1;

+    var columnNumber = 0;

+    while (0 <= index && index < sourceText.length) {

+      columnNumber++;

+      var codeUnit = sourceText.codeUnitAt(index);

+      if (codeUnit == $CR || codeUnit == $LF) {

+        break;

+      }

+      index--;

+    }

+    return columnNumber;

+  }

+

+  int get column {

+    if (_column == null) {

+      _column = _computeColumn();

+    }

+    return _column;

+  }

+

+  int get offset => _span.begin;

+

+  int get length => _span.end - _span.begin;

+

+  String get text => _script.text.substring(_span.begin, _span.end);

+

+  Uri get sourceUri => _script.uri;

+

+  String get sourceText => _script.text;

+}

diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
new file mode 100644
index 0000000..0a22d4d
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_member_mirrors.dart
@@ -0,0 +1,288 @@
+// 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.mirrors;

+

+//------------------------------------------------------------------------------

+// Member mirrors implementation.

+//------------------------------------------------------------------------------

+

+abstract class Dart2JsMemberMirror extends Dart2JsElementMirror {

+

+  Dart2JsMemberMirror(Dart2JsMirrorSystem system, Element element)

+      : super(system, element);

+

+  bool get isStatic => false;

+}

+

+

+class Dart2JsMethodKind {

+  static const Dart2JsMethodKind REGULAR = const Dart2JsMethodKind("regular");

+  static const Dart2JsMethodKind GENERATIVE =

+      const Dart2JsMethodKind("generative");

+  static const Dart2JsMethodKind REDIRECTING =

+      const Dart2JsMethodKind("redirecting");

+  static const Dart2JsMethodKind CONST = const Dart2JsMethodKind("const");

+  static const Dart2JsMethodKind FACTORY = const Dart2JsMethodKind("factory");

+  static const Dart2JsMethodKind GETTER = const Dart2JsMethodKind("getter");

+  static const Dart2JsMethodKind SETTER = const Dart2JsMethodKind("setter");

+  static const Dart2JsMethodKind OPERATOR = const Dart2JsMethodKind("operator");

+

+  final String text;

+

+  const Dart2JsMethodKind(this.text);

+

+  String toString() => text;

+}

+

+

+String _getOperatorFromOperatorName(String name) {

+  Map<String, String> mapping = const {

+    'eq': '==',

+    'not': '~',

+    'index': '[]',

+    'indexSet': '[]=',

+    'mul': '*',

+    'div': '/',

+    'mod': '%',

+    'tdiv': '~/',

+    'add': '+',

+    'sub': '-',

+    'shl': '<<',

+    'shr': '>>',

+    'ge': '>=',

+    'gt': '>',

+    'le': '<=',

+    'lt': '<',

+    'and': '&',

+    'xor': '^',

+    'or': '|',

+  };

+  String newName = mapping[name];

+  if (newName == null) {

+    throw new Exception('Unhandled operator name: $name');

+  }

+  return newName;

+}

+

+class Dart2JsMethodMirror extends Dart2JsMemberMirror

+    implements MethodMirror {

+  final Dart2JsDeclarationMirror owner;

+  final String _simpleNameString;

+  final Dart2JsMethodKind _kind;

+

+  Dart2JsMethodMirror._internal(Dart2JsDeclarationMirror owner,

+      FunctionElement function,

+      String this._simpleNameString,

+      Dart2JsMethodKind this._kind)

+      : this.owner = owner,

+        super(owner.mirrorSystem, function);

+

+  factory Dart2JsMethodMirror(Dart2JsDeclarationMirror owner,

+                              FunctionElement function) {

+    String realName = function.name;

+    // TODO(ahe): This method should not be calling

+    // Elements.operatorNameToIdentifier.

+    String simpleName =

+        Elements.operatorNameToIdentifier(function.name);

+    Dart2JsMethodKind kind;

+    if (function.kind == ElementKind.GETTER) {

+      kind = Dart2JsMethodKind.GETTER;

+    } else if (function.kind == ElementKind.SETTER) {

+      kind = Dart2JsMethodKind.SETTER;

+      simpleName = '$simpleName=';

+    } else if (function.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {

+      // TODO(johnniwinther): Support detection of redirecting constructors.

+      if (function.modifiers.isConst()) {

+        kind = Dart2JsMethodKind.CONST;

+      } else {

+        kind = Dart2JsMethodKind.GENERATIVE;

+      }

+    } else if (function.modifiers.isFactory()) {

+      // TODO(johnniwinther): Support detection of redirecting constructors.

+      kind = Dart2JsMethodKind.FACTORY;

+    } else if (realName == 'unary-') {

+      // TODO(johnniwinther): Use a constant for 'unary-'.

+      kind = Dart2JsMethodKind.OPERATOR;

+      // Simple name is 'unary-'.

+      simpleName = 'unary-';

+    } else if (simpleName.startsWith('operator\$')) {

+      String str = simpleName.substring(9);

+      simpleName = 'operator';

+      kind = Dart2JsMethodKind.OPERATOR;

+      simpleName = _getOperatorFromOperatorName(str);

+    } else {

+      kind = Dart2JsMethodKind.REGULAR;

+    }

+    return new Dart2JsMethodMirror._internal(owner, function,

+        simpleName, kind);

+  }

+

+  FunctionElement get _function => _element;

+

+  bool get isTopLevel => owner is LibraryMirror;

+

+  // TODO(johnniwinther): This seems stale and broken.

+  Symbol get constructorName => isConstructor ? simpleName : const Symbol('');

+

+  bool get isConstructor

+      => isGenerativeConstructor || isConstConstructor ||

+         isFactoryConstructor || isRedirectingConstructor;

+

+  bool get isSynthetic => false;

+

+  bool get isStatic => _function.modifiers.isStatic();

+

+  List<ParameterMirror> get parameters {

+    return _parametersFromFunctionSignature(this,

+        _function.computeSignature(mirrorSystem.compiler));

+  }

+

+  TypeMirror get returnType => owner._getTypeMirror(

+      _function.computeSignature(mirrorSystem.compiler).returnType);

+

+  bool get isAbstract => _function.isAbstract;

+

+  bool get isRegularMethod => !(isGetter || isSetter || isConstructor);

+

+  bool get isConstConstructor => _kind == Dart2JsMethodKind.CONST;

+

+  bool get isGenerativeConstructor => _kind == Dart2JsMethodKind.GENERATIVE;

+

+  bool get isRedirectingConstructor => _kind == Dart2JsMethodKind.REDIRECTING;

+

+  bool get isFactoryConstructor => _kind == Dart2JsMethodKind.FACTORY;

+

+  bool get isGetter => _kind == Dart2JsMethodKind.GETTER;

+

+  bool get isSetter => _kind == Dart2JsMethodKind.SETTER;

+

+  bool get isOperator => _kind == Dart2JsMethodKind.OPERATOR;

+

+  DeclarationMirror lookupInScope(String name) {

+    for (Dart2JsParameterMirror parameter in parameters) {

+      if (parameter._element.name == name) {

+        return parameter;

+      }

+    }

+    return super.lookupInScope(name);

+  }

+

+  // TODO(johnniwinther): Should this really be in the interface of

+  // [MethodMirror]?

+  String get source => location.sourceText;

+

+  String toString() => 'Mirror on method ${_element.name}';

+}

+

+class Dart2JsFieldMirror extends Dart2JsMemberMirror implements VariableMirror {

+  final Dart2JsDeclarationMirror owner;

+  VariableElement _variable;

+

+  Dart2JsFieldMirror(Dart2JsDeclarationMirror owner,

+                     VariableElement variable)

+      : this.owner = owner,

+        this._variable = variable,

+        super(owner.mirrorSystem, variable);

+

+  Element get _beginElement => _variable.variables;

+

+  bool get isTopLevel => owner is LibraryMirror;

+

+  bool get isStatic => _variable.modifiers.isStatic();

+

+  bool get isFinal => _variable.modifiers.isFinal();

+

+  bool get isConst => _variable.modifiers.isConst();

+

+  TypeMirror get type =>

+      owner._getTypeMirror(_variable.computeType(mirrorSystem.compiler));

+}

+

+class Dart2JsParameterMirror extends Dart2JsMemberMirror

+    implements ParameterMirror {

+  final Dart2JsDeclarationMirror owner;

+  final bool isOptional;

+  final bool isNamed;

+

+  factory Dart2JsParameterMirror(Dart2JsDeclarationMirror owner,

+                                 VariableElement element,

+                                 {bool isOptional: false,

+                                  bool isNamed: false}) {

+    if (element is FieldParameterElement) {

+      return new Dart2JsFieldParameterMirror(

+          owner, element, isOptional, isNamed);

+    }

+    return new Dart2JsParameterMirror._normal(

+        owner, element, isOptional, isNamed);

+  }

+

+  Dart2JsParameterMirror._normal(Dart2JsDeclarationMirror owner,

+                                 VariableElement element,

+                                 this.isOptional,

+                                 this.isNamed)

+    : this.owner = owner,

+      super(owner.mirrorSystem, element);

+

+  Element get _beginElement => _variableElement.variables;

+

+  VariableElement get _variableElement => _element;

+

+  TypeMirror get type => owner._getTypeMirror(

+      _variableElement.computeType(mirrorSystem.compiler),

+      _variableElement.variables.functionSignature);

+

+

+  bool get isFinal => false;

+

+  bool get isConst => false;

+

+  InstanceMirror get defaultValue {

+    if (hasDefaultValue) {

+      Constant constant = mirrorSystem.compiler.constantHandler

+          .getConstantForVariable(_variableElement);

+      assert(invariant(_variableElement, constant != null,

+          message: "Missing constant for parameter "

+                   "$_variableElement with default value."));

+      return _convertConstantToInstanceMirror(mirrorSystem, constant);

+    }

+    return null;

+  }

+

+  bool get hasDefaultValue {

+    return _variableElement.cachedNode.asSendSet() != null;

+  }

+

+  bool get isInitializingFormal => false;

+

+  VariableMirror get initializedField => null;

+}

+

+class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror {

+

+  Dart2JsFieldParameterMirror(Dart2JsDeclarationMirror method,

+                              FieldParameterElement element,

+                              bool isOptional,

+                              bool isNamed)

+      : super._normal(method, element, isOptional, isNamed);

+

+  FieldParameterElement get _fieldParameterElement => _element;

+

+  TypeMirror get type {

+    VariableListElement variables = _fieldParameterElement.variables;

+    VariableDefinitions node = variables.parseNode(mirrorSystem.compiler);

+    if (node.type != null) {

+      return super.type;

+    }

+    // Use the field type for initializing formals with no type annotation.

+    return owner._getTypeMirror(

+      _fieldParameterElement.fieldElement.computeType(mirrorSystem.compiler),

+      _fieldParameterElement.fieldElement.variables.functionSignature);

+  }

+

+  bool get isInitializingFormal => true;

+

+  VariableMirror get initializedField => new Dart2JsFieldMirror(

+      owner.owner, _fieldParameterElement.fieldElement);

+}

diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
deleted file mode 100644
index 453882a..0000000
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ /dev/null
@@ -1,1873 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library mirrors_dart2js;
-
-import 'dart:async';
-
-import '../../compiler.dart' as api;
-import '../elements/elements.dart';
-import '../apiimpl.dart' as apiimpl;
-import '../scanner/scannerlib.dart';
-import '../resolution/resolution.dart' show Scope;
-import '../dart2jslib.dart';
-import '../dart_types.dart';
-import '../tree/tree.dart';
-import '../util/util.dart' show Spannable, Link;
-import '../util/characters.dart' show $CR, $LF;
-
-import 'mirrors.dart';
-import 'mirrors_util.dart';
-import 'util.dart';
-
-//------------------------------------------------------------------------------
-// Utility types and functions for the dart2js mirror system
-//------------------------------------------------------------------------------
-
-bool _isPrivate(String name) {
-  return name.startsWith('_');
-}
-
-List<ParameterMirror> _parametersFromFunctionSignature(
-    Dart2JsMirrorSystem system,
-    Dart2JsMethodMirror method,
-    FunctionSignature signature) {
-  var parameters = <ParameterMirror>[];
-  Link<Element> link = signature.requiredParameters;
-  while (!link.isEmpty) {
-    parameters.add(new Dart2JsParameterMirror(
-        system, method, link.head, isOptional: false, isNamed: false));
-    link = link.tail;
-  }
-  link = signature.optionalParameters;
-  bool isNamed = signature.optionalParametersAreNamed;
-  while (!link.isEmpty) {
-    parameters.add(new Dart2JsParameterMirror(
-        system, method, link.head, isOptional: true, isNamed: isNamed));
-    link = link.tail;
-  }
-  return parameters;
-}
-
-Dart2JsTypeMirror _convertTypeToTypeMirror(
-    Dart2JsMirrorSystem system,
-    DartType type,
-    InterfaceType defaultType,
-    [FunctionSignature functionSignature]) {
-  if (type == null) {
-    return new Dart2JsInterfaceTypeMirror(system, defaultType);
-  } else if (type is InterfaceType) {
-    if (type == system.compiler.types.dynamicType) {
-      return new Dart2JsDynamicMirror(system, type);
-    } else {
-      return new Dart2JsInterfaceTypeMirror(system, type);
-    }
-  } else if (type is TypeVariableType) {
-    return new Dart2JsTypeVariableMirror(system, type);
-  } else if (type is FunctionType) {
-    return new Dart2JsFunctionTypeMirror(system, type, functionSignature);
-  } else if (type is VoidType) {
-    return new Dart2JsVoidMirror(system, type);
-  } else if (type is TypedefType) {
-    return new Dart2JsTypedefMirror(system, type);
-  } else if (type is MalformedType) {
-    // TODO(johnniwinther): We need a mirror on malformed types.
-    return system.dynamicType;
-  }
-  system.compiler.internalError("Unexpected type $type of kind ${type.kind}");
-}
-
-Iterable<Dart2JsMemberMirror> _convertElementMemberToMemberMirrors(
-    Dart2JsContainerMirror library, Element element) {
-  if (element.isSynthesized) {
-    return const <Dart2JsMemberMirror>[];
-  } else if (element is VariableElement) {
-    return <Dart2JsMemberMirror>[new Dart2JsFieldMirror(library, element)];
-  } else if (element is FunctionElement) {
-    return <Dart2JsMemberMirror>[new Dart2JsMethodMirror(library, element)];
-  } else if (element is AbstractFieldElement) {
-    var members = <Dart2JsMemberMirror>[];
-    AbstractFieldElement field = element;
-    if (field.getter != null) {
-      members.add(new Dart2JsMethodMirror(library, field.getter));
-    }
-    if (field.setter != null) {
-      members.add(new Dart2JsMethodMirror(library, field.setter));
-    }
-    return members;
-  }
-  library.mirrors.compiler.internalError(
-      "Unexpected member type $element ${element.kind}");
-}
-
-MethodMirror _convertElementMethodToMethodMirror(Dart2JsContainerMirror library,
-                                                 Element element) {
-  if (element is FunctionElement) {
-    return new Dart2JsMethodMirror(library, element);
-  } else {
-    return null;
-  }
-}
-
-InstanceMirror _convertConstantToInstanceMirror(Dart2JsMirrorSystem mirrors,
-                                                Constant constant) {
-  if (constant is BoolConstant) {
-    return new Dart2JsBoolConstantMirror(mirrors, constant);
-  } else if (constant is NumConstant) {
-    return new Dart2JsNumConstantMirror(mirrors, constant);
-  } else if (constant is StringConstant) {
-    return new Dart2JsStringConstantMirror(mirrors, constant);
-  } else if (constant is ListConstant) {
-    return new Dart2JsListConstantMirror(mirrors, constant);
-  } else if (constant is MapConstant) {
-    return new Dart2JsMapConstantMirror(mirrors, constant);
-  } else if (constant is TypeConstant) {
-    return new Dart2JsTypeConstantMirror(mirrors, constant);
-  } else if (constant is FunctionConstant) {
-    return new Dart2JsConstantMirror(mirrors, constant);
-  } else if (constant is NullConstant) {
-    return new Dart2JsNullConstantMirror(mirrors, constant);
-  } else if (constant is ConstructedConstant) {
-    return new Dart2JsConstructedConstantMirror(mirrors, constant);
-  }
-  mirrors.compiler.internalError("Unexpected constant $constant");
-}
-
-class Dart2JsMethodKind {
-  static const Dart2JsMethodKind REGULAR = const Dart2JsMethodKind("regular");
-  static const Dart2JsMethodKind GENERATIVE =
-      const Dart2JsMethodKind("generative");
-  static const Dart2JsMethodKind REDIRECTING =
-      const Dart2JsMethodKind("redirecting");
-  static const Dart2JsMethodKind CONST = const Dart2JsMethodKind("const");
-  static const Dart2JsMethodKind FACTORY = const Dart2JsMethodKind("factory");
-  static const Dart2JsMethodKind GETTER = const Dart2JsMethodKind("getter");
-  static const Dart2JsMethodKind SETTER = const Dart2JsMethodKind("setter");
-  static const Dart2JsMethodKind OPERATOR = const Dart2JsMethodKind("operator");
-
-  final String text;
-
-  const Dart2JsMethodKind(this.text);
-
-  String toString() => text;
-}
-
-
-String _getOperatorFromOperatorName(String name) {
-  Map<String, String> mapping = const {
-    'eq': '==',
-    'not': '~',
-    'index': '[]',
-    'indexSet': '[]=',
-    'mul': '*',
-    'div': '/',
-    'mod': '%',
-    'tdiv': '~/',
-    'add': '+',
-    'sub': '-',
-    'shl': '<<',
-    'shr': '>>',
-    'ge': '>=',
-    'gt': '>',
-    'le': '<=',
-    'lt': '<',
-    'and': '&',
-    'xor': '^',
-    'or': '|',
-  };
-  String newName = mapping[name];
-  if (newName == null) {
-    throw new Exception('Unhandled operator name: $name');
-  }
-  return newName;
-}
-
-//------------------------------------------------------------------------------
-// Analysis entry point.
-//------------------------------------------------------------------------------
-
-/**
- * Analyzes set of libraries and provides a mirror system which can be used for
- * static inspection of the source code.
- */
-// TODO(johnniwinther): Move this to [compiler/compiler.dart].
-Future<MirrorSystem> analyze(List<Uri> libraries,
-                             Uri libraryRoot,
-                             Uri packageRoot,
-                             api.CompilerInputProvider inputProvider,
-                             api.DiagnosticHandler diagnosticHandler,
-                             [List<String> options = const <String>[]]) {
-  if (!libraryRoot.path.endsWith("/")) {
-    throw new ArgumentError("libraryRoot must end with a /");
-  }
-  if (packageRoot != null && !packageRoot.path.endsWith("/")) {
-    throw new ArgumentError("packageRoot must end with a /");
-  }
-  options = new List<String>.from(options);
-  options.add('--analyze-only');
-  options.add('--analyze-signatures-only');
-  options.add('--analyze-all');
-  options.add('--categories=Client,Server');
-
-  bool compilationFailed = false;
-  void internalDiagnosticHandler(Uri uri, int begin, int end,
-                                 String message, api.Diagnostic kind) {
-    if (kind == api.Diagnostic.ERROR ||
-        kind == api.Diagnostic.CRASH) {
-      compilationFailed = true;
-    }
-    diagnosticHandler(uri, begin, end, message, kind);
-  }
-
-  Compiler compiler = new apiimpl.Compiler(inputProvider,
-                                           null,
-                                           internalDiagnosticHandler,
-                                           libraryRoot, packageRoot,
-                                           options,
-                                           const {});
-  compiler.librariesToAnalyzeWhenRun = libraries;
-  return compiler.run(null).then((bool success) {
-    if (success && !compilationFailed) {
-      return new Dart2JsMirrorSystem(compiler);
-    } else {
-      throw new StateError('Failed to create mirror system.');
-    }
-  });
-}
-
-//------------------------------------------------------------------------------
-// Dart2Js specific extensions of mirror interfaces
-//------------------------------------------------------------------------------
-
-abstract class Dart2JsMirror implements Mirror {
-  Dart2JsMirrorSystem get mirrors;
-}
-
-abstract class Dart2JsDeclarationMirror extends Dart2JsMirror
-    implements DeclarationMirror {
-
-  bool get isTopLevel => owner != null && owner is LibraryMirror;
-
-  bool get isPrivate => _isPrivate(simpleName);
-
-  /**
-   * Returns the first token for the source of this declaration, not including
-   * metadata annotations.
-   */
-  Token getBeginToken();
-
-  /**
-   * Returns the last token for the source of this declaration.
-   */
-  Token getEndToken();
-
-  /**
-   * Returns the script for the source of this declaration.
-   */
-  Script getScript();
-}
-
-abstract class Dart2JsTypeMirror extends Dart2JsDeclarationMirror
-    implements TypeMirror {
-}
-
-abstract class Dart2JsElementMirror extends Dart2JsDeclarationMirror {
-  final Dart2JsMirrorSystem mirrors;
-  final Element _element;
-  List<InstanceMirror> _metadata;
-
-  Dart2JsElementMirror(this.mirrors, this._element) {
-    assert (mirrors != null);
-    assert (_element != null);
-  }
-
-  /**
-   * Returns the element to be used to determine the begin token of this
-   * declaration and the metadata associated with this declaration.
-   *
-   * This indirection is needed to use the [VariableListElement] as the location
-   * for type and metadata information on a [VariableElement].
-   */
-  Element get _beginElement => _element;
-
-  String get simpleName => _element.name;
-
-  bool get isNameSynthetic => false;
-
-  /**
-   * Computes the first token for this declaration using the begin token of the
-   * element node or element position as indicator.
-   */
-  Token getBeginToken() {
-    // TODO(johnniwinther): Avoid calling [parseNode].
-    Node node = _beginElement.parseNode(mirrors.compiler);
-    if (node == null) {
-      return _beginElement.position();
-    }
-    return node.getBeginToken();
-  }
-
-  /**
-   * Computes the last token for this declaration using the end token of the
-   * element node or element position as indicator.
-   */
-  Token getEndToken() {
-    // TODO(johnniwinther): Avoid calling [parseNode].
-    Node node = _element.parseNode(mirrors.compiler);
-    if (node == null) {
-      return _element.position();
-    }
-    return node.getEndToken();
-  }
-
-  /**
-   * Returns the first token for the source of this declaration, including
-   * metadata annotations.
-   */
-  Token getFirstToken() {
-    if (!_beginElement.metadata.isEmpty) {
-      for (MetadataAnnotation metadata in _beginElement.metadata) {
-        if (metadata.beginToken != null) {
-          return metadata.beginToken;
-        }
-      }
-    }
-    return getBeginToken();
-  }
-
-  Script getScript() => _element.getCompilationUnit().script;
-
-  SourceLocation get location {
-    Token beginToken = getFirstToken();
-    Script script = getScript();
-    SourceSpan span;
-    if (beginToken == null) {
-      span = new SourceSpan(script.uri, 0, 0);
-    } else {
-      Token endToken = getEndToken();
-      span = mirrors.compiler.spanFromTokens(beginToken, endToken, script.uri);
-    }
-    return new Dart2JsSourceLocation(script, span);
-  }
-
-  String toString() => _element.toString();
-
-  void _appendCommentTokens(Token commentToken) {
-    while (commentToken != null && commentToken.kind == COMMENT_TOKEN) {
-      _metadata.add(new Dart2JsCommentInstanceMirror(
-          mirrors, commentToken.value));
-      commentToken = commentToken.next;
-    }
-  }
-
-  List<InstanceMirror> get metadata {
-    if (_metadata == null) {
-      _metadata = <InstanceMirror>[];
-      for (MetadataAnnotation metadata in _element.metadata) {
-        _appendCommentTokens(mirrors.compiler.commentMap[metadata.beginToken]);
-        metadata.ensureResolved(mirrors.compiler);
-        _metadata.add(
-            _convertConstantToInstanceMirror(mirrors, metadata.value));
-      }
-      _appendCommentTokens(mirrors.compiler.commentMap[getBeginToken()]);
-    }
-    // TODO(johnniwinther): Return an unmodifiable list instead.
-    return new List<InstanceMirror>.from(_metadata);
-  }
-
-  DeclarationMirror lookupInScope(String name) {
-    // TODO(11653): Support lookup of constructors.
-    Scope scope = _element.buildScope();
-    Element result;
-    int index = name.indexOf('.');
-    if (index != -1) {
-      // Lookup [: prefix.id :].
-      String prefix = name.substring(0, index);
-      String id = name.substring(index+1);
-      result = scope.lookup(prefix);
-      if (result != null && result.isPrefix()) {
-        PrefixElement prefix = result;
-        result = prefix.lookupLocalMember(id);
-      } else {
-        result = null;
-      }
-    } else {
-      // Lookup [: id :].
-      result = scope.lookup(name);
-    }
-    if (result == null || result.isPrefix()) return null;
-    return _convertElementToDeclarationMirror(mirrors, result);
-  }
-
-  bool operator ==(var other) {
-    if (identical(this, other)) return true;
-    if (other == null) return false;
-    if (other is! Dart2JsElementMirror) return false;
-    return _element == other._element &&
-           owner == other.owner;
-  }
-
-  int get hashCode {
-    return 13 * _element.hashCode + 17 * owner.hashCode;
-  }
-}
-
-abstract class Dart2JsMemberMirror extends Dart2JsElementMirror
-    implements MemberMirror {
-
-  Dart2JsMemberMirror(Dart2JsMirrorSystem system, Element element)
-      : super(system, element);
-
-  bool get isConstructor => false;
-
-  bool get isVariable => false;
-
-  bool get isMethod => false;
-
-  bool get isStatic => false;
-
-  bool get isParameter => false;
-}
-
-//------------------------------------------------------------------------------
-// Mirror system implementation.
-//------------------------------------------------------------------------------
-
-class Dart2JsMirrorSystem extends MirrorSystem {
-  final Compiler compiler;
-  Map<Uri, Dart2JsLibraryMirror> _libraries;
-  Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap;
-
-  Dart2JsMirrorSystem(this.compiler)
-    : _libraryMap = new Map<LibraryElement, Dart2JsLibraryMirror>();
-
-  void _ensureLibraries() {
-    if (_libraries == null) {
-      _libraries = new Map<Uri, Dart2JsLibraryMirror>();
-      compiler.libraries.forEach((_, LibraryElement v) {
-        var mirror = new Dart2JsLibraryMirror(mirrors, v);
-        _libraries[mirror.uri] = mirror;
-        _libraryMap[v] = mirror;
-      });
-    }
-  }
-
-  Map<Uri, LibraryMirror> get libraries {
-    _ensureLibraries();
-    return new FilteredImmutableMap<Uri, LibraryMirror>(_libraries,
-        (library) => new bool.fromEnvironment("list_all_libraries") ||
-                     !library._element.isInternalLibrary);
-  }
-
-  Dart2JsLibraryMirror _getLibrary(LibraryElement element) =>
-      _libraryMap[element];
-
-  Dart2JsMirrorSystem get mirrors => this;
-
-  TypeMirror get dynamicType =>
-      _convertTypeToTypeMirror(this, compiler.types.dynamicType, null);
-
-  TypeMirror get voidType =>
-      _convertTypeToTypeMirror(this, compiler.types.voidType, null);
-}
-
-abstract class Dart2JsContainerMirror extends Dart2JsElementMirror
-    implements ContainerMirror {
-  Map<String, MemberMirror> _members;
-
-  Dart2JsContainerMirror(Dart2JsMirrorSystem system, Element element)
-      : super(system, element);
-
-  void _ensureMembers();
-
-  Map<String, MemberMirror> get members {
-    _ensureMembers();
-    return new ImmutableMapWrapper<String, MemberMirror>(_members);
-  }
-
-  Map<String, MethodMirror> get functions {
-    _ensureMembers();
-    return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>(
-        _members,
-        (MemberMirror member) => member is MethodMirror ? member : null);
-  }
-
-  Map<String, MethodMirror> get getters {
-    _ensureMembers();
-    return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>(
-        _members,
-        (MemberMirror member) =>
-            member is MethodMirror && member.isGetter ? member : null);
-  }
-
-  Map<String, MethodMirror> get setters {
-    _ensureMembers();
-    return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>(
-        _members,
-        (MemberMirror member) =>
-            member is MethodMirror && member.isSetter ? member : null);
-  }
-
-  Map<String, VariableMirror> get variables {
-    _ensureMembers();
-    return new AsFilteredImmutableMap<String, MemberMirror, VariableMirror>(
-        _members,
-        (MemberMirror member) => member is VariableMirror ? member : null);
-  }
-}
-
-class Dart2JsLibraryMirror extends Dart2JsContainerMirror
-    implements LibraryMirror {
-  Map<String, ClassMirror> _classes;
-  List<LibraryDependencyMirror> _libraryDependencies;
-
-
-  Dart2JsLibraryMirror(Dart2JsMirrorSystem system, LibraryElement library)
-      : super(system, library);
-
-  LibraryElement get _library => _element;
-
-  Uri get uri => _library.canonicalUri;
-
-  DeclarationMirror get owner => null;
-
-  bool get isPrivate => false;
-
-  LibraryMirror library() => this;
-
-  /**
-   * Returns the library name (for libraries with a library tag) or the script
-   * file name (for scripts without a library tag). The latter case is used to
-   * provide a 'library name' for scripts, to use for instance in dartdoc.
-   */
-  String get simpleName {
-    if (_library.libraryTag != null) {
-      return _library.libraryTag.name.toString();
-    } else {
-      // Use the file name as script name.
-      String path = _library.canonicalUri.path;
-      return path.substring(path.lastIndexOf('/') + 1);
-    }
-  }
-
-  String get qualifiedName => simpleName;
-
-  void _ensureClasses() {
-    if (_classes == null) {
-      _classes = <String, ClassMirror>{};
-      _library.forEachLocalMember((Element e) {
-        if (e.isClass()) {
-          ClassElement classElement = e;
-          classElement.ensureResolved(mirrors.compiler);
-          var type = new Dart2JsClassMirror.fromLibrary(this, classElement);
-          assert(invariant(_library, !_classes.containsKey(type.simpleName),
-              message: "Type name '${type.simpleName}' "
-                       "is not unique in $_library."));
-          _classes[type.simpleName] = type;
-        } else if (e.isTypedef()) {
-          var type = new Dart2JsTypedefMirror.fromLibrary(this,
-              e.computeType(mirrors.compiler));
-          assert(invariant(_library, !_classes.containsKey(type.simpleName),
-              message: "Type name '${type.simpleName}' "
-                       "is not unique in $_library."));
-          _classes[type.simpleName] = type;
-        }
-      });
-    }
-  }
-
-  void _ensureMembers() {
-    if (_members == null) {
-      _members = <String, MemberMirror>{};
-      _library.forEachLocalMember((Element e) {
-        if (!e.isClass() && !e.isTypedef()) {
-          // TODO(ahe): I think it is incorrect to filter out classes
-          // and typedefs.  See http://dartbug.com/10371.
-          for (var member in _convertElementMemberToMemberMirrors(this, e)) {
-            assert(!_members.containsKey(member.simpleName));
-            _members[member.simpleName] = member;
-          }
-        }
-      });
-    }
-  }
-
-  Map<String, ClassMirror> get classes {
-    _ensureClasses();
-    return new ImmutableMapWrapper<String, ClassMirror>(_classes);
-  }
-
-  /**
-   * Computes the first token of this library using the first library tag as
-   * indicator.
-   */
-  Token getBeginToken() {
-    if (_library.libraryTag != null) {
-      return _library.libraryTag.getBeginToken();
-    } else if (!_library.tags.isEmpty) {
-      return _library.tags.reverse().head.getBeginToken();
-    }
-    return null;
-  }
-
-  /**
-   * Computes the first token of this library using the last library tag as
-   * indicator.
-   */
-  Token getEndToken() {
-    if (!_library.tags.isEmpty) {
-      return _library.tags.head.getEndToken();
-    }
-    return null;
-  }
-
-  void _ensureLibraryDependenciesAnalyzed() {
-    if (_libraryDependencies == null) {
-      _libraryDependencies = <LibraryDependencyMirror>[];
-      for (LibraryTag node in _library.tags.reverse()) {
-        LibraryDependency libraryDependency = node.asLibraryDependency();
-        if (libraryDependency != null) {
-          LibraryElement targetLibraryElement =
-              _library.getLibraryFromTag(libraryDependency);
-          assert(targetLibraryElement != null);
-          LibraryMirror targetLibrary =
-              mirrors._getLibrary(targetLibraryElement);
-          _libraryDependencies.add(new Dart2JsLibraryDependencyMirror(
-              libraryDependency, this, targetLibrary));
-        }
-      }
-    }
-  }
-
-  List<LibraryDependencyMirror> get libraryDependencies {
-    _ensureLibraryDependenciesAnalyzed();
-    return _libraryDependencies;
-  }
-}
-
-class Dart2JsLibraryDependencyMirror implements LibraryDependencyMirror {
-  final LibraryDependency _node;
-  final Dart2JsLibraryMirror _sourceLibrary;
-  final Dart2JsLibraryMirror _targetLibrary;
-  List<CombinatorMirror> _combinators;
-
-  Dart2JsLibraryDependencyMirror(this._node,
-                                 this._sourceLibrary,
-                                 this._targetLibrary);
-
-  SourceLocation get location {
-    return new Dart2JsSourceLocation(
-      _sourceLibrary._library.entryCompilationUnit.script,
-      _sourceLibrary.mirrors.compiler.spanFromNode(_node));
-  }
-
-  List<CombinatorMirror> get combinators {
-    if (_combinators == null) {
-      _combinators = <CombinatorMirror>[];
-      if (_node.combinators != null) {
-        for (Combinator combinator in _node.combinators.nodes) {
-          List<String> identifiers = <String>[];
-          for (Identifier identifier in combinator.identifiers.nodes) {
-            identifiers.add(identifier.source);
-          }
-          _combinators.add(new Dart2JsCombinatorMirror(
-              identifiers, isShow: combinator.isShow));
-        }
-      }
-    }
-    return _combinators;
-  }
-
-  LibraryMirror get sourceLibrary => _sourceLibrary;
-
-  LibraryMirror get targetLibrary => _targetLibrary;
-
-  String get prefix {
-    Import import = _node.asImport();
-    if (import != null && import.prefix != null) {
-      return import.prefix.source;
-    }
-    return null;
-  }
-
-  bool get isImport => _node.asImport() != null;
-
-  bool get isExport => _node.asExport() != null;
-}
-
-class Dart2JsCombinatorMirror implements CombinatorMirror {
-  final List<String> identifiers;
-  final bool isShow;
-
-  Dart2JsCombinatorMirror(this.identifiers, {bool isShow: true})
-      : this.isShow = isShow;
-
-  bool get isHide => !isShow;
-}
-
-class Dart2JsSourceLocation implements SourceLocation {
-  final Script _script;
-  final SourceSpan _span;
-  int _line;
-  int _column;
-
-  Dart2JsSourceLocation(this._script, this._span);
-
-  int _computeLine() {
-    var sourceFile = _script.file;
-    if (sourceFile != null) {
-      return sourceFile.getLine(offset) + 1;
-    }
-    var index = 0;
-    var lineNumber = 0;
-    while (index <= offset && index < sourceText.length) {
-      index = sourceText.indexOf('\n', index) + 1;
-      if (index <= 0) break;
-      lineNumber++;
-    }
-    return lineNumber;
-  }
-
-  int get line {
-    if (_line == null) {
-      _line = _computeLine();
-    }
-    return _line;
-  }
-
-  int _computeColumn() {
-    if (length == 0) return 0;
-
-    var sourceFile = _script.file;
-    if (sourceFile != null) {
-      return sourceFile.getColumn(sourceFile.getLine(offset), offset) + 1;
-    }
-    int index = offset - 1;
-    var columnNumber = 0;
-    while (0 <= index && index < sourceText.length) {
-      columnNumber++;
-      var codeUnit = sourceText.codeUnitAt(index);
-      if (codeUnit == $CR || codeUnit == $LF) {
-        break;
-      }
-      index--;
-    }
-    return columnNumber;
-  }
-
-  int get column {
-    if (_column == null) {
-      _column = _computeColumn();
-    }
-    return _column;
-  }
-
-  int get offset => _span.begin;
-
-  int get length => _span.end - _span.begin;
-
-  String get text => _script.text.substring(_span.begin, _span.end);
-
-  Uri get sourceUri => _script.uri;
-
-  String get sourceText => _script.text;
-}
-
-class Dart2JsParameterMirror extends Dart2JsMemberMirror
-    implements ParameterMirror {
-  final MethodMirror _method;
-  final bool isOptional;
-  final bool isNamed;
-
-  factory Dart2JsParameterMirror(Dart2JsMirrorSystem system,
-                                 MethodMirror method,
-                                 VariableElement element,
-                                 {bool isOptional: false,
-                                  bool isNamed: false}) {
-    if (element is FieldParameterElement) {
-      return new Dart2JsFieldParameterMirror(system,
-          method, element, isOptional, isNamed);
-    }
-    return new Dart2JsParameterMirror._normal(system,
-        method, element, isOptional, isNamed);
-  }
-
-  Dart2JsParameterMirror._normal(Dart2JsMirrorSystem system,
-                         this._method,
-                         VariableElement element,
-                         this.isOptional,
-                         this.isNamed)
-    : super(system, element);
-
-  Element get _beginElement => _variableElement.variables;
-
-  DeclarationMirror get owner => _method;
-
-  VariableElement get _variableElement => _element;
-
-  String get qualifiedName => '${_method.qualifiedName}#${simpleName}';
-
-  TypeMirror get type => _convertTypeToTypeMirror(mirrors,
-      _variableElement.computeType(mirrors.compiler),
-      mirrors.compiler.types.dynamicType,
-      _variableElement.variables.functionSignature);
-
-
-  bool get isFinal => false;
-
-  bool get isConst => false;
-
-  String get defaultValue {
-    if (hasDefaultValue) {
-      SendSet expression = _variableElement.cachedNode.asSendSet();
-      return unparse(expression.arguments.head);
-    }
-    return null;
-  }
-
-  bool get hasDefaultValue {
-    return _variableElement.cachedNode != null &&
-        _variableElement.cachedNode is SendSet;
-  }
-
-  bool get isInitializingFormal => false;
-
-  VariableMirror get initializedField => null;
-}
-
-class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror {
-
-  Dart2JsFieldParameterMirror(Dart2JsMirrorSystem system,
-                              MethodMirror method,
-                              FieldParameterElement element,
-                              bool isOptional,
-                              bool isNamed)
-      : super._normal(system, method, element, isOptional, isNamed);
-
-  FieldParameterElement get _fieldParameterElement => _element;
-
-  TypeMirror get type {
-    VariableListElement variables = _fieldParameterElement.variables;
-    VariableDefinitions node = variables.parseNode(mirrors.compiler);
-    if (node.type != null) {
-      return super.type;
-    }
-    // Use the field type for initializing formals with no type annotation.
-    return _convertTypeToTypeMirror(mirrors,
-      _fieldParameterElement.fieldElement.computeType(mirrors.compiler),
-      mirrors.compiler.types.dynamicType,
-      _variableElement.variables.functionSignature);
-  }
-
-  bool get isInitializingFormal => true;
-
-  VariableMirror get initializedField => new Dart2JsFieldMirror(
-      _method.owner, _fieldParameterElement.fieldElement);
-}
-
-//------------------------------------------------------------------------------
-// Declarations
-//------------------------------------------------------------------------------
-class Dart2JsClassMirror extends Dart2JsContainerMirror
-    implements Dart2JsTypeMirror, ClassMirror {
-  final Dart2JsLibraryMirror library;
-  List<TypeVariableMirror> _typeVariables;
-
-  Dart2JsClassMirror(Dart2JsMirrorSystem system, ClassElement _class)
-      : this.library = system._getLibrary(_class.getLibrary()),
-        super(system, _class);
-
-  ClassElement get _class => _element;
-
-  Dart2JsClassMirror.fromLibrary(Dart2JsLibraryMirror library,
-                                 ClassElement _class)
-      : this.library = library,
-        super(library.mirrors, _class);
-
-  DeclarationMirror get owner => library;
-
-  String get qualifiedName => '${library.qualifiedName}.${simpleName}';
-
-  void _ensureMembers() {
-    if (_members == null) {
-      _members = <String, Dart2JsMemberMirror>{};
-      _class.forEachMember((_, e) {
-        for (var member in _convertElementMemberToMemberMirrors(this, e)) {
-          assert(!_members.containsKey(member.simpleName));
-          _members[member.simpleName] = member;
-        }
-      });
-    }
-  }
-
-  Map<String, MethodMirror> get methods => functions;
-
-  Map<String, MethodMirror> get constructors {
-    _ensureMembers();
-    return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>(
-        _members, (m) => m.isConstructor ? m : null);
-  }
-
-  bool get isObject => _class == mirrors.compiler.objectClass;
-
-  bool get isDynamic => false;
-
-  bool get isVoid => false;
-
-  bool get isTypeVariable => false;
-
-  bool get isTypedef => false;
-
-  bool get isFunction => false;
-
-  ClassMirror get originalDeclaration => this;
-
-  ClassMirror get superclass {
-    if (_class.supertype != null) {
-      return new Dart2JsInterfaceTypeMirror(mirrors, _class.supertype);
-    }
-    return null;
-  }
-
-  ClassMirror get mixin {
-    if (_class.isMixinApplication) {
-      MixinApplicationElement mixinApplication = _class;
-      return new Dart2JsInterfaceTypeMirror(mirrors,
-                                            mixinApplication.mixinType);
-    }
-    return this;
-  }
-
-  bool get isNameSynthetic {
-    if (_class.isMixinApplication) {
-      MixinApplicationElement mixinApplication = _class;
-      return mixinApplication.isUnnamedMixinApplication;
-    }
-    return false;
-  }
-
-  List<ClassMirror> get superinterfaces {
-    var list = <ClassMirror>[];
-    Link<DartType> link = _class.interfaces;
-    while (!link.isEmpty) {
-      var type = _convertTypeToTypeMirror(mirrors, link.head,
-                                          mirrors.compiler.types.dynamicType);
-      list.add(type);
-      link = link.tail;
-    }
-    return list;
-  }
-
-  bool get isClass => true;
-
-  bool get isAbstract => _class.modifiers.isAbstract();
-
-  bool get isOriginalDeclaration => true;
-
-  List<TypeMirror> get typeArguments {
-    throw new UnsupportedError(
-        'Declarations do not have type arguments');
-  }
-
-  List<TypeVariableMirror> get typeVariables {
-    if (_typeVariables == null) {
-      _typeVariables = <TypeVariableMirror>[];
-      _class.ensureResolved(mirrors.compiler);
-      for (TypeVariableType typeVariable in _class.typeVariables) {
-        _typeVariables.add(
-            new Dart2JsTypeVariableMirror(mirrors, typeVariable));
-      }
-    }
-    return _typeVariables;
-  }
-
-  bool operator ==(other) {
-    if (identical(this, other)) {
-      return true;
-    }
-    if (other is! ClassMirror) {
-      return false;
-    }
-    if (library != other.library) {
-      return false;
-    }
-    if (!identical(isOriginalDeclaration, other.isOriginalDeclaration)) {
-      return false;
-    }
-    return qualifiedName == other.qualifiedName;
-  }
-}
-
-class Dart2JsTypedefMirror extends Dart2JsTypeElementMirror
-    implements Dart2JsTypeMirror, TypedefMirror {
-  final Dart2JsLibraryMirror _library;
-  List<TypeVariableMirror> _typeVariables;
-  TypeMirror _definition;
-
-  Dart2JsTypedefMirror(Dart2JsMirrorSystem system, TypedefType _typedef)
-      : this._library = system._getLibrary(_typedef.element.getLibrary()),
-        super(system, _typedef);
-
-  Dart2JsTypedefMirror.fromLibrary(Dart2JsLibraryMirror library,
-                                   TypedefType _typedef)
-      : this._library = library,
-        super(library.mirrors, _typedef);
-
-  TypedefType get _typedef => _type;
-
-  String get qualifiedName => '${library.qualifiedName}.${simpleName}';
-
-  LibraryMirror get library => _library;
-
-  bool get isTypedef => true;
-
-  List<TypeMirror> get typeArguments {
-    throw new UnsupportedError(
-        'Declarations do not have type arguments');
-  }
-
-  List<TypeVariableMirror> get typeVariables {
-    if (_typeVariables == null) {
-      _typeVariables = <TypeVariableMirror>[];
-      for (TypeVariableType typeVariable in _typedef.typeArguments) {
-        _typeVariables.add(
-            new Dart2JsTypeVariableMirror(mirrors, typeVariable));
-      }
-    }
-    return _typeVariables;
-  }
-
-  TypeMirror get value {
-    if (_definition == null) {
-      // TODO(johnniwinther): Should be [ensureResolved].
-      mirrors.compiler.resolveTypedef(_typedef.element);
-      _definition = _convertTypeToTypeMirror(
-          mirrors,
-          _typedef.element.alias,
-          mirrors.compiler.types.dynamicType,
-          _typedef.element.functionSignature);
-    }
-    return _definition;
-  }
-
-  ClassMirror get originalDeclaration => this;
-
-  // TODO(johnniwinther): How should a typedef respond to these?
-  ClassMirror get superclass => null;
-
-  List<ClassMirror> get superinterfaces => const <ClassMirror>[];
-
-  // TODO(johnniwinther): Refactor [TypedefMirror] to not extend [ClassMirror]
-  // and remove this.
-  ClassMirror get mixin => this;
-
-  bool get isClass => false;
-
-  bool get isOriginalDeclaration => true;
-
-  bool get isAbstract => false;
-}
-
-class Dart2JsTypeVariableMirror extends Dart2JsTypeElementMirror
-    implements TypeVariableMirror {
-  final TypeVariableType _typeVariableType;
-  ClassMirror _declarer;
-
-  Dart2JsTypeVariableMirror(Dart2JsMirrorSystem system,
-                            TypeVariableType typeVariableType)
-    : this._typeVariableType = typeVariableType,
-      super(system, typeVariableType) {
-      assert(_typeVariableType != null);
-  }
-
-
-  String get qualifiedName => '${declarer.qualifiedName}.${simpleName}';
-
-  ClassMirror get declarer {
-    if (_declarer == null) {
-      if (_typeVariableType.element.enclosingElement.isClass()) {
-        _declarer = new Dart2JsClassMirror(mirrors,
-            _typeVariableType.element.enclosingElement);
-      } else if (_typeVariableType.element.enclosingElement.isTypedef()) {
-        _declarer = new Dart2JsTypedefMirror(mirrors,
-            _typeVariableType.element.enclosingElement.computeType(
-                mirrors.compiler));
-      }
-    }
-    return _declarer;
-  }
-
-  LibraryMirror get library => declarer.library;
-
-  DeclarationMirror get owner => declarer;
-
-  bool get isTypeVariable => true;
-
-  TypeMirror get upperBound => _convertTypeToTypeMirror(
-      mirrors,
-      _typeVariableType.element.bound,
-      mirrors.compiler.objectClass.computeType(mirrors.compiler));
-
-  bool operator ==(var other) {
-    if (identical(this, other)) {
-      return true;
-    }
-    if (other is! TypeVariableMirror) {
-      return false;
-    }
-    if (declarer != other.declarer) {
-      return false;
-    }
-    return qualifiedName == other.qualifiedName;
-  }
-}
-
-
-//------------------------------------------------------------------------------
-// Types
-//------------------------------------------------------------------------------
-
-abstract class Dart2JsTypeElementMirror extends Dart2JsElementMirror
-    implements Dart2JsTypeMirror {
-  final DartType _type;
-
-  Dart2JsTypeElementMirror(Dart2JsMirrorSystem system, DartType type)
-    : super(system, type.element),
-      this._type = type;
-
-  String get simpleName => _type.name;
-
-  DeclarationMirror get owner => library;
-
-  LibraryMirror get library {
-    return mirrors._getLibrary(_type.element.getLibrary());
-  }
-
-  bool get isObject => false;
-
-  bool get isVoid => false;
-
-  bool get isDynamic => false;
-
-  bool get isTypeVariable => false;
-
-  bool get isTypedef => false;
-
-  bool get isFunction => false;
-
-  String toString() => _type.toString();
-
-  Map<String, MemberMirror> get members => const <String, MemberMirror>{};
-
-  Map<String, MethodMirror> get constructors => const <String, MethodMirror>{};
-
-  Map<String, MethodMirror> get methods => const <String, MethodMirror>{};
-
-  Map<String, MethodMirror> get getters => const <String, MethodMirror>{};
-
-  Map<String, MethodMirror> get setters => const <String, MethodMirror>{};
-
-  Map<String, VariableMirror> get variables => const <String, VariableMirror>{};
-}
-
-class Dart2JsInterfaceTypeMirror extends Dart2JsTypeElementMirror
-    implements ClassMirror {
-  List<TypeMirror> _typeArguments;
-
-  Dart2JsInterfaceTypeMirror(Dart2JsMirrorSystem system,
-                             InterfaceType interfaceType)
-      : super(system, interfaceType);
-
-  InterfaceType get _interfaceType => _type;
-
-  bool get isNameSynthetic => originalDeclaration.isNameSynthetic;
-
-  String get qualifiedName => originalDeclaration.qualifiedName;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  Map<String, MemberMirror> get members => originalDeclaration.members;
-
-  bool get isObject => mirrors.compiler.objectClass == _type.element;
-
-  // TODO(johnniwinther): How to show malformed types?
-  bool get isDynamic => _type.isDynamic;
-
-  ClassMirror get originalDeclaration
-      => new Dart2JsClassMirror(mirrors, _type.element);
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  ClassMirror get superclass => originalDeclaration.superclass;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  ClassMirror get mixin {
-    if (originalDeclaration.mixin == originalDeclaration) {
-      return this;
-    }
-    return originalDeclaration.mixin;
-  }
-
-  bool get isClass => originalDeclaration.isClass;
-
-  bool get isAbstract => originalDeclaration.isAbstract;
-
-  bool get isPrivate => originalDeclaration.isPrivate;
-
-  bool get isOriginalDeclaration => false;
-
-  List<TypeMirror> get typeArguments {
-    if (_typeArguments == null) {
-      _typeArguments = <TypeMirror>[];
-      if (!_interfaceType.isRaw) {
-        Link<DartType> type = _interfaceType.typeArguments;
-        while (type != null && type.head != null) {
-          _typeArguments.add(_convertTypeToTypeMirror(mirrors, type.head,
-              mirrors.compiler.types.dynamicType));
-          type = type.tail;
-        }
-      }
-    }
-    return _typeArguments;
-  }
-
-  List<TypeVariableMirror> get typeVariables =>
-      originalDeclaration.typeVariables;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  Map<String, MethodMirror> get constructors =>
-      originalDeclaration.constructors;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  Map<String, MethodMirror> get methods => originalDeclaration.methods;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  Map<String, MethodMirror> get setters => originalDeclaration.setters;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  Map<String, MethodMirror> get getters => originalDeclaration.getters;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  Map<String, VariableMirror> get variables => originalDeclaration.variables;
-
-  bool operator ==(other) {
-    if (identical(this, other)) {
-      return true;
-    }
-    if (other is! ClassMirror) {
-      return false;
-    }
-    if (other.isOriginalDeclaration) {
-      return false;
-    }
-    if (originalDeclaration != other.originalDeclaration) {
-      return false;
-    }
-    var thisTypeArguments = typeArguments.iterator;
-    var otherTypeArguments = other.typeArguments.iterator;
-    while (thisTypeArguments.moveNext()) {
-      if (!otherTypeArguments.moveNext()) return false;
-      if (thisTypeArguments.current != otherTypeArguments.current) {
-        return false;
-      }
-    }
-    return !otherTypeArguments.moveNext();
-  }
-}
-
-
-class Dart2JsFunctionTypeMirror extends Dart2JsTypeElementMirror
-    implements FunctionTypeMirror {
-  final FunctionSignature _functionSignature;
-  List<ParameterMirror> _parameters;
-
-  Dart2JsFunctionTypeMirror(Dart2JsMirrorSystem system,
-                            FunctionType functionType, this._functionSignature)
-      : super(system, functionType) {
-    assert (_functionSignature != null);
-  }
-
-  FunctionType get _functionType => _type;
-
-  // TODO(johnniwinther): Is this the qualified name of a function type?
-  String get qualifiedName => originalDeclaration.qualifiedName;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  Map<String, MemberMirror> get members {
-    var method = callMethod;
-    if (method != null) {
-      var map = new Map<String, MemberMirror>.from(
-          originalDeclaration.members);
-      var name = method.qualifiedName;
-      assert(!map.containsKey(name));
-      map[name] = method;
-      return new ImmutableMapWrapper<String, MemberMirror>(map);
-    }
-    return originalDeclaration.members;
-  }
-
-  bool get isFunction => true;
-
-  MethodMirror get callMethod => _convertElementMethodToMethodMirror(
-      mirrors._getLibrary(_functionType.element.getLibrary()),
-      _functionType.element);
-
-  ClassMirror get originalDeclaration
-      => new Dart2JsClassMirror(mirrors, mirrors.compiler.functionClass);
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  ClassMirror get superclass => originalDeclaration.superclass;
-
-  // TODO(johnniwinther): Substitute type arguments for type variables.
-  List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces;
-
-  ClassMirror get mixin => this;
-
-  bool get isClass => originalDeclaration.isClass;
-
-  bool get isPrivate => originalDeclaration.isPrivate;
-
-  bool get isOriginalDeclaration => false;
-
-  bool get isAbstract => false;
-
-  List<TypeMirror> get typeArguments => const <TypeMirror>[];
-
-  List<TypeVariableMirror> get typeVariables =>
-      originalDeclaration.typeVariables;
-
-  TypeMirror get returnType {
-    return _convertTypeToTypeMirror(mirrors, _functionType.returnType,
-                                    mirrors.compiler.types.dynamicType);
-  }
-
-  List<ParameterMirror> get parameters {
-    if (_parameters == null) {
-      _parameters = _parametersFromFunctionSignature(mirrors, callMethod,
-                                                     _functionSignature);
-    }
-    return _parameters;
-  }
-}
-
-class Dart2JsVoidMirror extends Dart2JsTypeElementMirror {
-
-  Dart2JsVoidMirror(Dart2JsMirrorSystem system, VoidType voidType)
-      : super(system, voidType);
-
-  VoidType get _voidType => _type;
-
-  String get qualifiedName => simpleName;
-
-  /**
-   * The void type has no location.
-   */
-  SourceLocation get location => null;
-
-  /**
-   * The void type has no library.
-   */
-  LibraryMirror get library => null;
-
-  bool get isVoid => true;
-
-  bool operator ==(other) {
-    if (identical(this, other)) {
-      return true;
-    }
-    if (other is! TypeMirror) {
-      return false;
-    }
-    return other.isVoid;
-  }
-}
-
-
-class Dart2JsDynamicMirror extends Dart2JsTypeElementMirror {
-  Dart2JsDynamicMirror(Dart2JsMirrorSystem system, InterfaceType voidType)
-      : super(system, voidType);
-
-  InterfaceType get _dynamicType => _type;
-
-  String get qualifiedName => simpleName;
-
-  /**
-   * The dynamic type has no location.
-   */
-  SourceLocation get location => null;
-
-  /**
-   * The dynamic type has no library.
-   */
-  LibraryMirror get library => null;
-
-  bool get isDynamic => true;
-
-  bool operator ==(other) {
-    if (identical(this, other)) {
-      return true;
-    }
-    if (other is! TypeMirror) {
-      return false;
-    }
-    return other.isDynamic;
-  }
-}
-
-//------------------------------------------------------------------------------
-// Member mirrors implementation.
-//------------------------------------------------------------------------------
-
-class Dart2JsMethodMirror extends Dart2JsMemberMirror
-    implements MethodMirror {
-  final Dart2JsContainerMirror _objectMirror;
-  final String simpleName;
-  final Dart2JsMethodKind _kind;
-
-  Dart2JsMethodMirror._internal(Dart2JsContainerMirror objectMirror,
-      FunctionElement function,
-      String this.simpleName,
-      Dart2JsMethodKind this._kind)
-      : this._objectMirror = objectMirror,
-        super(objectMirror.mirrors, function);
-
-  factory Dart2JsMethodMirror(Dart2JsContainerMirror objectMirror,
-                              FunctionElement function) {
-    String realName = function.name;
-    // TODO(ahe): This method should not be calling
-    // Elements.operatorNameToIdentifier.
-    String simpleName =
-        Elements.operatorNameToIdentifier(function.name);
-    Dart2JsMethodKind kind;
-    if (function.kind == ElementKind.GETTER) {
-      kind = Dart2JsMethodKind.GETTER;
-    } else if (function.kind == ElementKind.SETTER) {
-      kind = Dart2JsMethodKind.SETTER;
-      simpleName = '$simpleName=';
-    } else if (function.kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
-      // TODO(johnniwinther): Support detection of redirecting constructors.
-      if (function.modifiers.isConst()) {
-        kind = Dart2JsMethodKind.CONST;
-      } else {
-        kind = Dart2JsMethodKind.GENERATIVE;
-      }
-    } else if (function.modifiers.isFactory()) {
-      kind = Dart2JsMethodKind.FACTORY;
-    } else if (realName == 'unary-') {
-      kind = Dart2JsMethodKind.OPERATOR;
-      // Simple name is 'unary-'.
-      simpleName = Mirror.UNARY_MINUS;
-    } else if (simpleName.startsWith('operator\$')) {
-      String str = simpleName.substring(9);
-      simpleName = 'operator';
-      kind = Dart2JsMethodKind.OPERATOR;
-      simpleName = _getOperatorFromOperatorName(str);
-    } else {
-      kind = Dart2JsMethodKind.REGULAR;
-    }
-    return new Dart2JsMethodMirror._internal(objectMirror, function,
-        simpleName, kind);
-  }
-
-  FunctionElement get _function => _element;
-
-  String get qualifiedName
-      => '${owner.qualifiedName}.$simpleName';
-
-  DeclarationMirror get owner => _objectMirror;
-
-  bool get isTopLevel => _objectMirror is LibraryMirror;
-
-  bool get isConstructor
-      => isGenerativeConstructor || isConstConstructor ||
-         isFactoryConstructor || isRedirectingConstructor;
-
-  bool get isMethod => !isConstructor;
-
-  bool get isStatic => _function.modifiers.isStatic();
-
-  List<ParameterMirror> get parameters {
-    return _parametersFromFunctionSignature(mirrors, this,
-        _function.computeSignature(mirrors.compiler));
-  }
-
-  TypeMirror get returnType => _convertTypeToTypeMirror(
-      mirrors, _function.computeSignature(mirrors.compiler).returnType,
-      mirrors.compiler.types.dynamicType);
-
-  bool get isAbstract => _function.isAbstract;
-
-  bool get isRegularMethod => !(isGetter || isSetter || isConstructor);
-
-  bool get isConstConstructor => _kind == Dart2JsMethodKind.CONST;
-
-  bool get isGenerativeConstructor => _kind == Dart2JsMethodKind.GENERATIVE;
-
-  bool get isRedirectingConstructor => _kind == Dart2JsMethodKind.REDIRECTING;
-
-  bool get isFactoryConstructor => _kind == Dart2JsMethodKind.FACTORY;
-
-  bool get isGetter => _kind == Dart2JsMethodKind.GETTER;
-
-  bool get isSetter => _kind == Dart2JsMethodKind.SETTER;
-
-  bool get isOperator => _kind == Dart2JsMethodKind.OPERATOR;
-
-  DeclarationMirror lookupInScope(String name) {
-    for (ParameterMirror parameter in parameters) {
-      if (parameter.simpleName == name) {
-        return parameter;
-      }
-    }
-    return super.lookupInScope(name);
-  }
-}
-
-class Dart2JsFieldMirror extends Dart2JsMemberMirror implements VariableMirror {
-  Dart2JsContainerMirror _objectMirror;
-  VariableElement _variable;
-
-  Dart2JsFieldMirror(Dart2JsContainerMirror objectMirror,
-                     VariableElement variable)
-      : this._objectMirror = objectMirror,
-        this._variable = variable,
-        super(objectMirror.mirrors, variable);
-
-  Element get _beginElement => _variable.variables;
-
-  String get qualifiedName
-      => '${owner.qualifiedName}.$simpleName';
-
-  DeclarationMirror get owner => _objectMirror;
-
-  bool get isTopLevel => _objectMirror is LibraryMirror;
-
-  bool get isVariable => true;
-
-  bool get isStatic => _variable.modifiers.isStatic();
-
-  bool get isFinal => _variable.modifiers.isFinal();
-
-  bool get isConst => _variable.modifiers.isConst();
-
-  TypeMirror get type => _convertTypeToTypeMirror(mirrors,
-      _variable.computeType(mirrors.compiler),
-      mirrors.compiler.types.dynamicType);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Mirrors on constant values used for metadata.
-////////////////////////////////////////////////////////////////////////////////
-
-class Dart2JsConstantMirror extends InstanceMirror {
-  final Dart2JsMirrorSystem mirrors;
-  final Constant _constant;
-
-  Dart2JsConstantMirror(this.mirrors, this._constant);
-
-  ClassMirror get type {
-    return new Dart2JsClassMirror(mirrors,
-        _constant.computeType(mirrors.compiler).element);
-  }
-
-  bool get hasReflectee => false;
-
-  get reflectee {
-    // TODO(johnniwinther): Which exception/error should be thrown here?
-    throw new UnsupportedError('InstanceMirror does not have a reflectee');
-  }
-
-  InstanceMirror getField(String fieldName) {
-    // TODO(johnniwinther): Which exception/error should be thrown here?
-    throw new UnsupportedError('InstanceMirror does not have a reflectee');
-  }
-}
-
-class Dart2JsNullConstantMirror extends Dart2JsConstantMirror {
-  Dart2JsNullConstantMirror(Dart2JsMirrorSystem mirrors, NullConstant constant)
-      : super(mirrors, constant);
-
-  NullConstant get _constant => super._constant;
-
-  bool get hasReflectee => true;
-
-  get reflectee => null;
-}
-
-class Dart2JsBoolConstantMirror extends Dart2JsConstantMirror {
-  Dart2JsBoolConstantMirror(Dart2JsMirrorSystem mirrors, BoolConstant constant)
-      : super(mirrors, constant);
-
-  Dart2JsBoolConstantMirror.fromBool(Dart2JsMirrorSystem mirrors, bool value)
-      : super(mirrors, value ? new TrueConstant() : new FalseConstant());
-
-  BoolConstant get _constant => super._constant;
-
-  bool get hasReflectee => true;
-
-  get reflectee => _constant is TrueConstant;
-}
-
-class Dart2JsStringConstantMirror extends Dart2JsConstantMirror {
-  Dart2JsStringConstantMirror(Dart2JsMirrorSystem mirrors,
-                              StringConstant constant)
-      : super(mirrors, constant);
-
-  Dart2JsStringConstantMirror.fromString(Dart2JsMirrorSystem mirrors,
-                                         String text)
-      : super(mirrors, new StringConstant(new DartString.literal(text)));
-
-  StringConstant get _constant => super._constant;
-
-  bool get hasReflectee => true;
-
-  get reflectee => _constant.value.slowToString();
-}
-
-class Dart2JsNumConstantMirror extends Dart2JsConstantMirror {
-  Dart2JsNumConstantMirror(Dart2JsMirrorSystem mirrors,
-                           NumConstant constant)
-      : super(mirrors, constant);
-
-  NumConstant get _constant => super._constant;
-
-  bool get hasReflectee => true;
-
-  get reflectee => _constant.value;
-}
-
-class Dart2JsListConstantMirror extends Dart2JsConstantMirror
-    implements ListInstanceMirror {
-  Dart2JsListConstantMirror(Dart2JsMirrorSystem mirrors,
-                            ListConstant constant)
-      : super(mirrors, constant);
-
-  ListConstant get _constant => super._constant;
-
-  int get length => _constant.length;
-
-  InstanceMirror operator[](int index) {
-    if (index < 0) throw new RangeError('Negative index');
-    if (index >= _constant.length) throw new RangeError('Index out of bounds');
-    return _convertConstantToInstanceMirror(mirrors, _constant.entries[index]);
-  }
-}
-
-class Dart2JsMapConstantMirror extends Dart2JsConstantMirror
-    implements MapInstanceMirror {
-  List<String> _listCache;
-
-  Dart2JsMapConstantMirror(Dart2JsMirrorSystem mirrors,
-                           MapConstant constant)
-      : super(mirrors, constant);
-
-  MapConstant get _constant => super._constant;
-
-  List<String> get _list {
-    if (_listCache == null) {
-      _listCache = new List<String>(_constant.keys.entries.length);
-      int index = 0;
-      for (StringConstant keyConstant in _constant.keys.entries) {
-        _listCache[index] = keyConstant.value.slowToString();
-        index++;
-      }
-    }
-    return _listCache;
-  }
-
-  int get length => _constant.length;
-
-  Iterable<String> get keys {
-    // TODO(johnniwinther): Return an unmodifiable list instead.
-    return new List<String>.from(_list);
-  }
-
-  InstanceMirror operator[](String key) {
-    int index = _list.indexOf(key);
-    if (index == -1) return null;
-    return _convertConstantToInstanceMirror(mirrors, _constant.values[index]);
-  }
-}
-
-class Dart2JsTypeConstantMirror extends Dart2JsConstantMirror
-    implements TypeInstanceMirror {
-
-  Dart2JsTypeConstantMirror(Dart2JsMirrorSystem mirrors,
-                            TypeConstant constant)
-      : super(mirrors, constant);
-
-  TypeConstant get _constant => super._constant;
-
-  TypeMirror get representedType => _convertTypeToTypeMirror(
-      mirrors, _constant.representedType, mirrors.compiler.types.dynamicType);
-}
-
-class Dart2JsConstructedConstantMirror extends Dart2JsConstantMirror {
-  Map<String,Constant> _fieldMapCache;
-
-  Dart2JsConstructedConstantMirror(Dart2JsMirrorSystem mirrors,
-                                   ConstructedConstant constant)
-      : super(mirrors, constant);
-
-  ConstructedConstant get _constant => super._constant;
-
-  Map<String,Constant> get _fieldMap {
-    if (_fieldMapCache == null) {
-      _fieldMapCache = new Map<String,Constant>();
-      if (identical(_constant.type.element.kind, ElementKind.CLASS)) {
-        var index = 0;
-        ClassElement element = _constant.type.element;
-        element.forEachInstanceField((_, Element field) {
-          String fieldName = field.name;
-          _fieldMapCache.putIfAbsent(fieldName, () => _constant.fields[index]);
-          index++;
-        }, includeSuperAndInjectedMembers: true);
-      }
-    }
-    return _fieldMapCache;
-  }
-
-  InstanceMirror getField(String fieldName) {
-    Constant fieldConstant = _fieldMap[fieldName];
-    if (fieldConstant != null) {
-      return _convertConstantToInstanceMirror(mirrors, fieldConstant);
-    }
-    return super.getField(fieldName);
-  }
-}
-
-class Dart2JsCommentInstanceMirror implements CommentInstanceMirror {
-  final Dart2JsMirrorSystem mirrors;
-  final String text;
-  String _trimmedText;
-
-  Dart2JsCommentInstanceMirror(this.mirrors, this.text);
-
-  ClassMirror get type {
-    return new Dart2JsClassMirror(mirrors, mirrors.compiler.documentClass);
-  }
-
-  bool get isDocComment => text.startsWith('/**') || text.startsWith('///');
-
-  String get trimmedText {
-    if (_trimmedText == null) {
-      _trimmedText = stripComment(text);
-    }
-    return _trimmedText;
-  }
-
-  bool get hasReflectee => false;
-
-  get reflectee {
-    // TODO(johnniwinther): Which exception/error should be thrown here?
-    throw new UnsupportedError('InstanceMirror does not have a reflectee');
-  }
-
-  InstanceMirror getField(String fieldName) {
-    if (fieldName == 'isDocComment') {
-      return new Dart2JsBoolConstantMirror.fromBool(mirrors, isDocComment);
-    } else if (fieldName == 'text') {
-      return new Dart2JsStringConstantMirror.fromString(mirrors, text);
-    } else if (fieldName == 'trimmedText') {
-      return new Dart2JsStringConstantMirror.fromString(mirrors, trimmedText);
-    }
-    // TODO(johnniwinther): Which exception/error should be thrown here?
-    throw new UnsupportedError('InstanceMirror does not have a reflectee');
-  }
-}
-
-_convertElementToMembers(Dart2JsLibraryMirror library, Element e) {
-  // TODO(ahe): This method creates new mirror objects which is not correct.
-  if (e.isClass()) {
-    ClassElement classElement = e;
-    classElement.ensureResolved(library.mirrors.compiler);
-    return [new Dart2JsClassMirror.fromLibrary(library, classElement)];
-  } else if (e.isTypedef()) {
-    return [new Dart2JsTypedefMirror.fromLibrary(
-          library, e.computeType(library.mirrors.compiler))];
-  } else {
-    return _convertElementMemberToMemberMirrors(library, e);
-  }
-}
-
-/**
- * Converts [element] into its corresponding [DeclarationMirror], if any.
- *
- * If [element] is an [AbstractFieldElement] the mirror for its getter is
- * returned or, if not present, the mirror for its setter.
- */
-DeclarationMirror _convertElementToDeclarationMirror(Dart2JsMirrorSystem system,
-                                                     Element element) {
-  if (element.isTypeVariable()) {
-    return new Dart2JsTypeVariableMirror(
-        system, element.computeType(system.compiler));
-  }
-
-  Dart2JsLibraryMirror library = system._libraryMap[element.getLibrary()];
-  if (element.isLibrary()) return library;
-  if (element.isTypedef()) {
-    return new Dart2JsTypedefMirror.fromLibrary(
-        library, element.computeType(system.compiler));
-  }
-
-  Dart2JsContainerMirror container = library;
-  if (element.getEnclosingClass() != null) {
-    container = new Dart2JsClassMirror.fromLibrary(
-        library, element.getEnclosingClass());
-  }
-  if (element.isClass()) return container;
-  if (element.isParameter()) {
-    MethodMirror method = _convertElementMethodToMethodMirror(
-        container, element.getOutermostEnclosingMemberOrTopLevel());
-    // TODO(johnniwinther): Find the right info for [isOptional] and [isNamed].
-    return new Dart2JsParameterMirror(
-        system, method, element, isOptional: false, isNamed: false);
-  }
-  Iterable<MemberMirror> members =
-      _convertElementMemberToMemberMirrors(container, element);
-  if (members.isEmpty) return null;
-  return members.first;
-}
-
-/**
- * Experimental API for accessing compilation units defined in a
- * library.
- */
-// TODO(ahe): Superclasses? Is this really a mirror?
-class Dart2JsCompilationUnitMirror extends Dart2JsMirror {
-  final Dart2JsLibraryMirror _library;
-  final CompilationUnitElement _element;
-
-  Dart2JsCompilationUnitMirror(this._element, this._library);
-
-  Dart2JsMirrorSystem get mirrors => _library.mirrors;
-
-  List<DeclarationMirror> get members {
-    // TODO(ahe): Should return an immutable List.
-    // TODO(johnniwinther): make sure that these are returned in declaration
-    // order.
-    List<DeclarationMirror> members= <DeclarationMirror>[];
-    _element.forEachLocalMember((m) {
-      members.addAll(_convertElementToMembers(_library, m));
-    });
-    return members;
-  }
-
-  Uri get uri => _element.script.uri;
-}
-
-/**
- * Transitional class that allows access to features that have not yet
- * made it to the mirror API.
- *
- * All API in this class is experimental.
- */
-class BackDoor {
-  /// Return the compilation units comprising [library].
-  static List<Mirror> compilationUnitsOf(Dart2JsLibraryMirror library) {
-    return library._library.compilationUnits.toList().map(
-        (cu) => new Dart2JsCompilationUnitMirror(cu, library)).toList();
-  }
-}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
new file mode 100644
index 0000000..a399a8c
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart
@@ -0,0 +1,468 @@
+// Copyright (c) 2012, 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.
+
+library dart2js.mirrors;
+
+import 'dart:collection' show UnmodifiableListView;
+
+import '../elements/elements.dart';
+import '../scanner/scannerlib.dart';
+import '../resolution/resolution.dart' show Scope;
+import '../dart2jslib.dart';
+import '../dart_types.dart';
+import '../tree/tree.dart';
+import '../util/util.dart' show Spannable, Link, LinkBuilder;
+import '../util/characters.dart' show $CR, $LF;
+
+import 'source_mirrors.dart';
+import 'mirrors_util.dart';
+import 'util.dart';
+
+part 'dart2js_library_mirror.dart';
+part 'dart2js_type_mirrors.dart';
+part 'dart2js_member_mirrors.dart';
+part 'dart2js_instance_mirrors.dart';
+
+//------------------------------------------------------------------------------
+// Utility types and functions for the dart2js mirror system
+//------------------------------------------------------------------------------
+
+bool _isPrivate(String name) {
+  return name.startsWith('_');
+}
+
+List<ParameterMirror> _parametersFromFunctionSignature(
+    Dart2JsDeclarationMirror owner,
+    FunctionSignature signature) {
+  var parameters = <ParameterMirror>[];
+  Link<Element> link = signature.requiredParameters;
+  while (!link.isEmpty) {
+    parameters.add(new Dart2JsParameterMirror(
+        owner, link.head, isOptional: false, isNamed: false));
+    link = link.tail;
+  }
+  link = signature.optionalParameters;
+  bool isNamed = signature.optionalParametersAreNamed;
+  while (!link.isEmpty) {
+    parameters.add(new Dart2JsParameterMirror(
+        owner, link.head, isOptional: true, isNamed: isNamed));
+    link = link.tail;
+  }
+  return parameters;
+}
+
+MethodMirror _convertElementMethodToMethodMirror(
+    Dart2JsDeclarationMirror library, Element element) {
+  if (element is FunctionElement) {
+    return new Dart2JsMethodMirror(library, element);
+  } else {
+    return null;
+  }
+}
+
+//------------------------------------------------------------------------------
+// Dart2Js specific extensions of mirror interfaces
+//------------------------------------------------------------------------------
+
+abstract class Dart2JsMirror implements Mirror {
+  Dart2JsMirrorSystem get mirrorSystem;
+}
+
+abstract class Dart2JsDeclarationMirror extends Dart2JsMirror
+    implements DeclarationSourceMirror {
+
+  bool get isTopLevel => owner != null && owner is LibraryMirror;
+
+  bool get isPrivate => _isPrivate(_simpleNameString);
+
+  String get _simpleNameString;
+
+  String get _qualifiedNameString {
+    var parent = owner;
+    if (parent is Dart2JsDeclarationMirror) {
+      return '${parent._qualifiedNameString}.${_simpleNameString}';
+    }
+    assert(parent == null);
+    return _simpleNameString;
+  }
+
+  Symbol get simpleName => symbolOf(_simpleNameString, getLibrary(this));
+
+  Symbol get qualifiedName => symbolOf(_qualifiedNameString, getLibrary(this));
+
+  /**
+   * Returns the first token for the source of this declaration, not including
+   * metadata annotations.
+   */
+  Token getBeginToken();
+
+  /**
+   * Returns the last token for the source of this declaration.
+   */
+  Token getEndToken();
+
+  /**
+   * Returns the script for the source of this declaration.
+   */
+  Script getScript();
+
+  /// Returns the type mirror for [type] in the context of this declaration.
+  TypeMirror _getTypeMirror(DartType type, [FunctionSignature signature]) {
+    return mirrorSystem._convertTypeToTypeMirror(type, signature);
+  }
+
+  /// Returns a list of the declaration mirrorSystem for [element].
+  Iterable<Dart2JsMemberMirror> _getDeclarationMirrors(Element element) {
+    if (element.isSynthesized) {
+      return const <Dart2JsMemberMirror>[];
+    } else if (element is VariableElement) {
+      return <Dart2JsMemberMirror>[new Dart2JsFieldMirror(this, element)];
+    } else if (element is FunctionElement) {
+      return <Dart2JsMemberMirror>[new Dart2JsMethodMirror(this, element)];
+    } else if (element is AbstractFieldElement) {
+      var members = <Dart2JsMemberMirror>[];
+      AbstractFieldElement field = element;
+      if (field.getter != null) {
+        members.add(new Dart2JsMethodMirror(this, field.getter));
+      }
+      if (field.setter != null) {
+        members.add(new Dart2JsMethodMirror(this, field.setter));
+      }
+      return members;
+    }
+    mirrorSystem.compiler.internalError(
+        "Unexpected member type $element ${element.kind}");
+  }
+
+}
+
+abstract class Dart2JsElementMirror extends Dart2JsDeclarationMirror {
+  final Dart2JsMirrorSystem mirrorSystem;
+  final Element _element;
+  List<InstanceMirror> _metadata;
+
+  Dart2JsElementMirror(this.mirrorSystem, this._element) {
+    assert (mirrorSystem != null);
+    assert (_element != null);
+  }
+
+  /**
+   * Returns the element to be used to determine the begin token of this
+   * declaration and the metadata associated with this declaration.
+   *
+   * This indirection is needed to use the [VariableListElement] as the location
+   * for type and metadata information on a [VariableElement].
+   */
+  Element get _beginElement => _element;
+
+  String get _simpleNameString => _element.name;
+
+  bool get isNameSynthetic => false;
+
+  /**
+   * Computes the first token for this declaration using the begin token of the
+   * element node or element position as indicator.
+   */
+  Token getBeginToken() {
+    // TODO(johnniwinther): Avoid calling [parseNode].
+    Node node = _beginElement.parseNode(mirrorSystem.compiler);
+    if (node == null) {
+      return _beginElement.position();
+    }
+    return node.getBeginToken();
+  }
+
+  /**
+   * Computes the last token for this declaration using the end token of the
+   * element node or element position as indicator.
+   */
+  Token getEndToken() {
+    // TODO(johnniwinther): Avoid calling [parseNode].
+    Node node = _element.parseNode(mirrorSystem.compiler);
+    if (node == null) {
+      return _element.position();
+    }
+    return node.getEndToken();
+  }
+
+  /**
+   * Returns the first token for the source of this declaration, including
+   * metadata annotations.
+   */
+  Token getFirstToken() {
+    if (!_beginElement.metadata.isEmpty) {
+      for (MetadataAnnotation metadata in _beginElement.metadata) {
+        if (metadata.beginToken != null) {
+          return metadata.beginToken;
+        }
+      }
+    }
+    return getBeginToken();
+  }
+
+  Script getScript() => _element.getCompilationUnit().script;
+
+  SourceLocation get location {
+    Token beginToken = getFirstToken();
+    Script script = getScript();
+    SourceSpan span;
+    if (beginToken == null) {
+      span = new SourceSpan(script.uri, 0, 0);
+    } else {
+      Token endToken = getEndToken();
+      span = mirrorSystem.compiler.spanFromTokens(
+          beginToken, endToken, script.uri);
+    }
+    return new Dart2JsSourceLocation(script, span);
+  }
+
+  String toString() => _element.toString();
+
+  void _appendCommentTokens(Token commentToken) {
+    while (commentToken != null && commentToken.kind == COMMENT_TOKEN) {
+      _metadata.add(new Dart2JsCommentInstanceMirror(
+          mirrorSystem, commentToken.value));
+      commentToken = commentToken.next;
+    }
+  }
+
+  List<InstanceMirror> get metadata {
+    if (_metadata == null) {
+      _metadata = <InstanceMirror>[];
+      for (MetadataAnnotation metadata in _element.metadata) {
+        _appendCommentTokens(
+            mirrorSystem.compiler.commentMap[metadata.beginToken]);
+        metadata.ensureResolved(mirrorSystem.compiler);
+        _metadata.add(
+            _convertConstantToInstanceMirror(mirrorSystem, metadata.value));
+      }
+      _appendCommentTokens(mirrorSystem.compiler.commentMap[getBeginToken()]);
+    }
+    // TODO(johnniwinther): Return an unmodifiable list instead.
+    return new List<InstanceMirror>.from(_metadata);
+  }
+
+  DeclarationMirror lookupInScope(String name) {
+    // TODO(11653): Support lookup of constructors.
+    Scope scope = _element.buildScope();
+    Element result;
+    int index = name.indexOf('.');
+    if (index != -1) {
+      // Lookup [: prefix.id :].
+      String prefix = name.substring(0, index);
+      String id = name.substring(index+1);
+      result = scope.lookup(prefix);
+      if (result != null && result.isPrefix()) {
+        PrefixElement prefix = result;
+        result = prefix.lookupLocalMember(id);
+      } else {
+        result = null;
+      }
+    } else {
+      // Lookup [: id :].
+      result = scope.lookup(name);
+    }
+    if (result == null || result.isPrefix()) return null;
+    return _convertElementToDeclarationMirror(mirrorSystem, result);
+  }
+
+  bool operator ==(var other) {
+    if (identical(this, other)) return true;
+    if (other == null) return false;
+    if (other is! Dart2JsElementMirror) return false;
+    return _element == other._element &&
+           owner == other.owner;
+  }
+
+  int get hashCode {
+    return 13 * _element.hashCode + 17 * owner.hashCode;
+  }
+}
+
+//------------------------------------------------------------------------------
+// Mirror system implementation.
+//------------------------------------------------------------------------------
+
+class Dart2JsMirrorSystem extends MirrorSystem {
+  final Compiler compiler;
+  Map<Uri, Dart2JsLibraryMirror> _libraries;
+  Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap;
+
+  Dart2JsMirrorSystem(this.compiler)
+    : _libraryMap = new Map<LibraryElement, Dart2JsLibraryMirror>();
+
+  IsolateMirror get isolate => null;
+
+  void _ensureLibraries() {
+    if (_libraries == null) {
+      _libraries = new Map<Uri, Dart2JsLibraryMirror>();
+      compiler.libraries.forEach((_, LibraryElement v) {
+        var mirror = new Dart2JsLibraryMirror(mirrorSystem, v);
+        _libraries[mirror.uri] = mirror;
+        _libraryMap[v] = mirror;
+      });
+    }
+  }
+
+  Map<Uri, LibraryMirror> get libraries {
+    _ensureLibraries();
+    return new FilteredImmutableMap<Uri, LibraryMirror>(_libraries,
+        (library) => const bool.fromEnvironment("list_all_libraries") ||
+                     !library._element.isInternalLibrary);
+  }
+
+  Dart2JsLibraryMirror _getLibrary(LibraryElement element) =>
+      _libraryMap[element];
+
+  Dart2JsMirrorSystem get mirrorSystem => this;
+
+  TypeMirror get dynamicType =>
+      _convertTypeToTypeMirror(compiler.types.dynamicType);
+
+  TypeMirror get voidType =>
+      _convertTypeToTypeMirror(compiler.types.voidType);
+
+  TypeMirror _convertTypeToTypeMirror(DartType type,
+                                      [FunctionSignature signature]) {
+    assert(type != null);
+    if (type.treatAsDynamic) {
+      return new Dart2JsDynamicMirror(this, type);
+    } else if (type is InterfaceType) {
+      if (type.typeArguments.isEmpty) {
+        return _getTypeDeclarationMirror(type.element);
+      } else {
+        return new Dart2JsInterfaceTypeMirror(this, type);
+      }
+    } else if (type is TypeVariableType) {
+      return new Dart2JsTypeVariableMirror(this, type);
+    } else if (type is FunctionType) {
+      return new Dart2JsFunctionTypeMirror(this, type, signature);
+    } else if (type is VoidType) {
+      return new Dart2JsVoidMirror(this, type);
+    } else if (type is TypedefType) {
+      if (type.typeArguments.isEmpty) {
+        return _getTypeDeclarationMirror(type.element);
+      } else {
+        return new Dart2JsTypedefMirror(this, type);
+      }
+    }
+    compiler.internalError("Unexpected type $type of kind ${type.kind}");
+  }
+
+  DeclarationMirror _getTypeDeclarationMirror(Element element) {
+    if (element.isClass()) {
+      return new Dart2JsClassDeclarationMirror(
+          this, element.computeType(compiler));
+    } else if (element.isTypedef()) {
+      return new Dart2JsTypedefDeclarationMirror(this,
+          element.computeType(compiler));
+    }
+  }
+}
+
+abstract class ContainerMixin {
+  Map<Symbol, DeclarationMirror> _declarations;
+
+  void _ensureDeclarations() {
+    if (_declarations == null) {
+      _declarations = <Symbol, DeclarationMirror>{};
+      _forEachElement((Element element) {
+        for (DeclarationMirror mirror in _getDeclarationMirrors(element)) {
+          assert(invariant(_element,
+              !_declarations.containsKey(mirror.simpleName),
+              message: "Declaration name '${nameOf(mirror)}' "
+                       "is not unique in $_element."));
+          _declarations[mirror.simpleName] = mirror;
+        }
+      });
+    }
+  }
+
+  Element get _element;
+
+  void _forEachElement(f(Element element));
+
+  Iterable<Dart2JsMemberMirror> _getDeclarationMirrors(Element element);
+
+  Map<Symbol, DeclarationMirror> get declarations {
+    _ensureDeclarations();
+    return new ImmutableMapWrapper<Symbol, DeclarationMirror>(_declarations);
+  }
+}
+
+/**
+ * Converts [element] into its corresponding [DeclarationMirror], if any.
+ *
+ * If [element] is an [AbstractFieldElement] the mirror for its getter is
+ * returned or, if not present, the mirror for its setter.
+ */
+DeclarationMirror _convertElementToDeclarationMirror(Dart2JsMirrorSystem system,
+                                                     Element element) {
+  if (element.isTypeVariable()) {
+    return new Dart2JsTypeVariableMirror(
+        system, element.computeType(system.compiler));
+  }
+
+  Dart2JsLibraryMirror library = system._libraryMap[element.getLibrary()];
+  if (element.isLibrary()) return library;
+  if (element.isTypedef()) {
+    return new Dart2JsTypedefMirror.fromLibrary(
+        library, element.computeType(system.compiler));
+  }
+
+  Dart2JsDeclarationMirror container = library;
+  if (element.getEnclosingClass() != null) {
+    container = system._getTypeDeclarationMirror(element.getEnclosingClass());
+  }
+  if (element.isClass()) return container;
+  if (element.isParameter()) {
+    Dart2JsMethodMirror method = _convertElementMethodToMethodMirror(
+        container, element.getOutermostEnclosingMemberOrTopLevel());
+    // TODO(johnniwinther): Find the right info for [isOptional] and [isNamed].
+    return new Dart2JsParameterMirror(
+        method, element, isOptional: false, isNamed: false);
+  }
+  Iterable<DeclarationMirror> members =
+      container._getDeclarationMirrors(element);
+  if (members.isEmpty) return null;
+  return members.first;
+}
+
+/**
+ * Experimental API for accessing compilation units defined in a
+ * library.
+ */
+// TODO(ahe): Superclasses? Is this really a mirror?
+class Dart2JsCompilationUnitMirror extends Dart2JsMirror
+    with ContainerMixin {
+  final Dart2JsLibraryMirror _library;
+  final CompilationUnitElement _element;
+
+  Dart2JsCompilationUnitMirror(this._element, this._library);
+
+  Dart2JsMirrorSystem get mirrorSystem => _library.mirrorSystem;
+
+  // TODO(johnniwinther): make sure that these are returned in declaration
+  // order.
+  void _forEachElement(f(Element element)) => _element.forEachLocalMember(f);
+
+  Iterable<DeclarationMirror> _getDeclarationMirrors(Element element) =>
+      _library._getDeclarationMirrors(element);
+
+  Uri get uri => _element.script.uri;
+}
+
+/**
+ * Transitional class that allows access to features that have not yet
+ * made it to the mirror API.
+ *
+ * All API in this class is experimental.
+ */
+class BackDoor {
+  /// Return the compilation units comprising [library].
+  static List<Mirror> compilationUnitsOf(Dart2JsLibraryMirror library) {
+    return library._element.compilationUnits.toList().map(
+        (cu) => new Dart2JsCompilationUnitMirror(cu, library)).toList();
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_type_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_type_mirrors.dart
new file mode 100644
index 0000000..64c54c4
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_type_mirrors.dart
@@ -0,0 +1,460 @@
+// 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.mirrors;

+

+//------------------------------------------------------------------------------

+// Types

+//------------------------------------------------------------------------------

+

+abstract class ClassMirrorMixin implements ClassSourceMirror {

+  bool get hasReflectedType => false;

+  Type get reflectedType {

+    throw new UnsupportedError("ClassMirror.reflectedType is not supported.");

+  }

+  InstanceMirror newInstance(Symbol constructorName,

+                             List positionalArguments,

+                             [Map<Symbol, dynamic> namedArguments]) {

+    throw new UnsupportedError("ClassMirror.newInstance is not supported.");

+  }

+}

+

+abstract class Dart2JsTypeMirror

+    extends Dart2JsElementMirror

+    implements TypeSourceMirror {

+  final DartType _type;

+

+  Dart2JsTypeMirror(Dart2JsMirrorSystem system, DartType type)

+    : super(system, type.element),

+      this._type = type;

+

+  String get _simpleNameString => _type.name;

+

+  Dart2JsDeclarationMirror get owner => library;

+

+  Dart2JsLibraryMirror get library {

+    return mirrorSystem._getLibrary(_type.element.getLibrary());

+  }

+

+  bool get isOriginalDeclaration => true;

+

+  TypeMirror get originalDeclaration => this;

+

+  List<TypeMirror> get typeArguments => const <TypeMirror>[];

+

+  List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];

+

+  TypeMirror createInstantiation(List<TypeMirror> typeArguments) {

+    if (typeArguments.isEmpty) return this;

+    throw new ArgumentError('Cannot create generic instantiation of $_type.');

+  }

+

+  bool get isVoid => false;

+

+  bool get isDynamic => false;

+

+  String toString() => _type.toString();

+}

+

+abstract class DeclarationMixin implements TypeMirror {

+

+  bool get isOriginalDeclaration => true;

+

+  TypeMirror get originalDeclaration => this;

+

+  List<TypeMirror> get typeArguments => const <TypeMirror>[];

+}

+

+abstract class Dart2JsGenericTypeMirror extends Dart2JsTypeMirror {

+  List<TypeMirror> _typeArguments;

+  List<TypeVariableMirror> _typeVariables;

+

+  Dart2JsGenericTypeMirror(Dart2JsMirrorSystem system, GenericType type)

+      : super(system, type);

+

+  TypeDeclarationElement get _element => super._element;

+

+  GenericType get _type => super._type;

+

+  bool get isOriginalDeclaration => false;

+

+  TypeMirror get originalDeclaration =>

+      mirrorSystem._getTypeDeclarationMirror(_element);

+

+  List<TypeMirror> get typeArguments {

+    if (_typeArguments == null) {

+      _typeArguments = <TypeMirror>[];

+      if (!_type.isRaw) {

+        Link<DartType> type = _type.typeArguments;

+        while (type != null && type.head != null) {

+          _typeArguments.add(_getTypeMirror(type.head));

+          type = type.tail;

+        }

+      }

+    }

+    return _typeArguments;

+  }

+

+  List<TypeVariableMirror> get typeVariables {

+    if (_typeVariables == null) {

+      _typeVariables = <TypeVariableMirror>[];

+      for (TypeVariableType typeVariable in _element.typeVariables) {

+        _typeVariables.add(

+            new Dart2JsTypeVariableMirror(mirrorSystem, typeVariable));

+      }

+    }

+    return _typeVariables;

+  }

+

+  Iterable<Dart2JsMemberMirror> _getDeclarationMirrors(Element element) {

+    if (element.isTypeVariable()) {

+      assert(invariant(_element, _element == element.enclosingElement,

+          message: 'Foreigned type variable element $element.'));

+      for (Dart2JsTypeVariableMirror mirror in typeVariables) {

+        if (mirror._element == element) return [mirror];

+      }

+    }

+    return super._getDeclarationMirrors(element);

+  }

+

+  TypeMirror _getTypeMirror(DartType type, [FunctionSignature signature]) {

+    return super._getTypeMirror(

+        type.subst(_type.typeArguments, _type.element.typeVariables),

+        signature);

+  }

+

+  TypeSourceMirror createInstantiation(

+      List<TypeSourceMirror> newTypeArguments) {

+    if (newTypeArguments.isEmpty) return owner._getTypeMirror(_type.asRaw());

+    if (newTypeArguments.length != typeVariables.length) {

+      throw new ArgumentError('Cannot create generic instantiation of $_type '

+                              'with ${newTypeArguments.length} arguments, '

+                              'expect ${typeVariables.length} arguments.');

+    }

+    LinkBuilder<DartType> builder = new LinkBuilder<DartType>();

+    for (TypeSourceMirror newTypeArgument in newTypeArguments) {

+      if (newTypeArgument.isVoid) {

+        throw new ArgumentError('Cannot use void as type argument.');

+      }

+      if (newTypeArgument is Dart2JsTypeMirror) {

+        builder.addLast(newTypeArgument._type);

+      } else {

+        throw new UnsupportedError(

+            'Cannot create instantiation using a type '

+            'mirror from a different mirrorSystem implementation.');

+      }

+    }

+    return owner._getTypeMirror(_type.createInstantiation(builder.toLink()));

+  }

+}

+

+class Dart2JsInterfaceTypeMirror

+    extends Dart2JsGenericTypeMirror

+    with ObjectMirrorMixin, InstanceMirrorMixin, ClassMirrorMixin,

+         ContainerMixin

+    implements ClassMirror {

+  Dart2JsInterfaceTypeMirror(Dart2JsMirrorSystem system,

+                             InterfaceType interfaceType)

+      : super(system, interfaceType);

+

+  ClassElement get _element => super._element;

+

+  InterfaceType get _type => super._type;

+

+  bool get isNameSynthetic  {

+    if (_element.isMixinApplication) {

+      MixinApplicationElement mixinApplication = _element;

+      return mixinApplication.isUnnamedMixinApplication;

+    }

+    return false;

+  }

+

+  void _forEachElement(f(Element element)) {

+    _element.forEachMember((_, element) => f(element));

+  }

+

+  ClassMirror get superclass {

+    if (_element.supertype != null) {

+      return _getTypeMirror(_element.supertype);

+    }

+    return null;

+  }

+

+  ClassMirror get mixin {

+    if (_element.isMixinApplication) {

+      MixinApplicationElement mixinApplication = _element;

+      return _getTypeMirror(mixinApplication.mixinType);

+    }

+    return this;

+  }

+

+  List<ClassMirror> get superinterfaces {

+    var list = <ClassMirror>[];

+    Link<DartType> link = _element.interfaces;

+    while (!link.isEmpty) {

+      var type = _getTypeMirror(link.head);

+      list.add(type);

+      link = link.tail;

+    }

+    return list;

+  }

+

+  Map<Symbol, MethodMirror> get instanceMembers => null;

+  Map<Symbol, MethodMirror> get staticMembers => null;

+

+  bool get isAbstract => _element.modifiers.isAbstract();

+

+  bool operator ==(other) {

+    if (identical(this, other)) {

+      return true;

+    }

+    if (other is! ClassMirror) {

+      return false;

+    }

+    return _type == other._type;

+  }

+

+  String toString() => 'Mirror on interface type $_type';

+}

+

+class Dart2JsClassDeclarationMirror

+    extends Dart2JsInterfaceTypeMirror

+    with DeclarationMixin {

+

+  Dart2JsClassDeclarationMirror(Dart2JsMirrorSystem system,

+                                InterfaceType type)

+      : super(system, type);

+

+  String toString() => 'Mirror on class ${_type.name}';

+}

+

+class Dart2JsTypedefMirror

+    extends Dart2JsGenericTypeMirror

+    implements TypedefMirror {

+  final Dart2JsLibraryMirror _library;

+  List<TypeVariableMirror> _typeVariables;

+  var _definition;

+

+  Dart2JsTypedefMirror(Dart2JsMirrorSystem system, TypedefType _typedef)

+      : this._library = system._getLibrary(_typedef.element.getLibrary()),

+        super(system, _typedef);

+

+  Dart2JsTypedefMirror.fromLibrary(Dart2JsLibraryMirror library,

+                                   TypedefType _typedef)

+      : this._library = library,

+        super(library.mirrorSystem, _typedef);

+

+  TypedefType get _typedef => _type;

+

+  LibraryMirror get library => _library;

+

+  bool get isTypedef => true;

+

+  FunctionTypeMirror get referent {

+    if (_definition == null) {

+      _definition = _getTypeMirror(

+          _typedef.element.alias,

+          _typedef.element.functionSignature);

+    }

+    return _definition;

+  }

+

+  bool get isClass => false;

+

+  bool get isAbstract => false;

+

+  String toString() => 'Mirror on typedef $_type';

+}

+

+class Dart2JsTypedefDeclarationMirror

+    extends Dart2JsTypedefMirror

+    with DeclarationMixin {

+  Dart2JsTypedefDeclarationMirror(Dart2JsMirrorSystem system,

+                                  TypedefType type)

+      : super(system, type);

+

+  String toString() => 'Mirror on typedef ${_type.name}';

+}

+

+class Dart2JsTypeVariableMirror extends Dart2JsTypeMirror

+    implements TypeVariableMirror {

+  Dart2JsDeclarationMirror _owner;

+

+  Dart2JsTypeVariableMirror(Dart2JsMirrorSystem system,

+                            TypeVariableType typeVariableType)

+    : super(system, typeVariableType);

+

+  TypeVariableType get _type => super._type;

+

+  Dart2JsDeclarationMirror get owner {

+    if (_owner == null) {

+      _owner = mirrorSystem._getTypeDeclarationMirror(

+          _type.element.enclosingElement);

+    }

+    return _owner;

+  }

+

+  TypeMirror get upperBound => owner._getTypeMirror(_type.element.bound);

+

+  bool operator ==(var other) {

+    if (identical(this, other)) {

+      return true;

+    }

+    if (other is! TypeVariableMirror) {

+      return false;

+    }

+    if (owner != other.owner) {

+      return false;

+    }

+    return qualifiedName == other.qualifiedName;

+  }

+

+  String toString() => 'Mirror on type variable $_type';

+}

+

+class Dart2JsFunctionTypeMirror extends Dart2JsTypeMirror

+    with ObjectMirrorMixin, InstanceMirrorMixin,

+         ClassMirrorMixin, DeclarationMixin

+    implements FunctionTypeMirror {

+  final FunctionSignature _functionSignature;

+  List<ParameterMirror> _parameters;

+

+  Dart2JsFunctionTypeMirror(Dart2JsMirrorSystem system,

+                            FunctionType functionType, this._functionSignature)

+      : super(system, functionType) {

+    assert (_functionSignature != null);

+  }

+

+  FunctionType get _type => super._type;

+

+  // TODO(johnniwinther): Is this the qualified name of a function type?

+  Symbol get qualifiedName => originalDeclaration.qualifiedName;

+

+  // TODO(johnniwinther): Substitute type arguments for type variables.

+  Map<Symbol, DeclarationMirror> get declarations {

+    var method = callMethod;

+    if (method != null) {

+      var map = new Map<Symbol, DeclarationMirror>.from(

+          originalDeclaration.declarations);

+      var name = method.qualifiedName;

+      assert(!map.containsKey(name));

+      map[name] = method;

+      return new ImmutableMapWrapper<Symbol, DeclarationMirror>(map);

+    }

+    return originalDeclaration.declarations;

+  }

+

+  bool get isFunction => true;

+

+  MethodMirror get callMethod => _convertElementMethodToMethodMirror(

+      mirrorSystem._getLibrary(_type.element.getLibrary()),

+      _type.element);

+

+  ClassMirror get originalDeclaration =>

+      mirrorSystem._getTypeDeclarationMirror(

+          mirrorSystem.compiler.functionClass);

+

+  // TODO(johnniwinther): Substitute type arguments for type variables.

+  ClassMirror get superclass => originalDeclaration.superclass;

+

+  // TODO(johnniwinther): Substitute type arguments for type variables.

+  List<ClassMirror> get superinterfaces => originalDeclaration.superinterfaces;

+

+  Map<Symbol, MethodMirror> get instanceMembers => null;

+  Map<Symbol, MethodMirror> get staticMembers => null;

+

+  ClassMirror get mixin => this;

+

+  bool get isPrivate => false;

+

+  bool get isAbstract => false;

+

+  List<TypeVariableMirror> get typeVariables =>

+      originalDeclaration.typeVariables;

+

+  TypeMirror get returnType => owner._getTypeMirror(_type.returnType);

+

+  List<ParameterMirror> get parameters {

+    if (_parameters == null) {

+      _parameters = _parametersFromFunctionSignature(owner,

+                                                     _functionSignature);

+    }

+    return _parameters;

+  }

+

+  String toString() => 'Mirror on function type $_type';

+}

+

+class Dart2JsVoidMirror extends Dart2JsTypeMirror {

+

+  Dart2JsVoidMirror(Dart2JsMirrorSystem system, VoidType voidType)

+      : super(system, voidType);

+

+  VoidType get _voidType => _type;

+

+  Symbol get qualifiedName => simpleName;

+

+  /**

+   * The void type has no location.

+   */

+  SourceLocation get location => null;

+

+  /**

+   * The void type has no library.

+   */

+  LibraryMirror get library => null;

+

+  List<InstanceMirror> get metadata => const <InstanceMirror>[];

+

+  bool get isVoid => true;

+

+  bool operator ==(other) {

+    if (identical(this, other)) {

+      return true;

+    }

+    if (other is! TypeMirror) {

+      return false;

+    }

+    return other.isVoid;

+  }

+

+  int get hashCode => 13 * _element.hashCode;

+

+  String toString() => 'Mirror on void';

+}

+

+class Dart2JsDynamicMirror extends Dart2JsTypeMirror {

+  Dart2JsDynamicMirror(Dart2JsMirrorSystem system, InterfaceType voidType)

+      : super(system, voidType);

+

+  InterfaceType get _dynamicType => _type;

+

+  Symbol get qualifiedName => simpleName;

+

+  /**

+   * The dynamic type has no location.

+   */

+  SourceLocation get location => null;

+

+  /**

+   * The dynamic type has no library.

+   */

+  LibraryMirror get library => null;

+

+  bool get isDynamic => true;

+

+  bool operator ==(other) {

+    if (identical(this, other)) {

+      return true;

+    }

+    if (other is! TypeMirror) {

+      return false;

+    }

+    return other.isDynamic;

+  }

+

+  int get hashCode => 13 * _element.hashCode;

+

+  String toString() => 'Mirror on dynamic';

+}

diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart
deleted file mode 100644
index 5acdfa0..0000000
--- a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart
+++ /dev/null
@@ -1,752 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library mirrors;
-
-/**
- * The main interface for the whole mirror system.
- */
-abstract class MirrorSystem {
-  /**
-   * Returns an unmodifiable map of all libraries in this mirror system.
-   */
-  Map<Uri, LibraryMirror> get libraries;
-
-  /**
-   * Returns an iterable of all libraries in the mirror system whose library
-   * name is [libraryName].
-   */
-  LibraryMirror findLibrary(String libraryName) {
-    return libraries.values.singleWhere(
-        (library) => library.simpleName == libraryName);
-  }
-
-  /**
-   * A mirror on the [:dynamic:] type.
-   */
-  TypeMirror get dynamicType;
-
-  /**
-   * A mirror on the [:void:] type.
-   */
-  TypeMirror get voidType;
-}
-
-
-/**
- * An entity in the mirror system.
- */
-abstract class Mirror {
-  static const String UNARY_MINUS = 'unary-';
-
-  // TODO(johnniwinther): Do we need this on all mirrors?
-  /**
-   * Returns the mirror system which contains this mirror.
-   */
-  MirrorSystem get mirrors;
-}
-
-abstract class DeclarationMirror implements Mirror {
-  /**
-   * The simple name of the entity. The simple name is unique within the
-   * scope of the entity declaration.
-   *
-   * The simple name is in most cases the declared single identifier name of
-   * the entity, such as 'method' for a method [:void method() {...}:]. For an
-   * unnamed constructor for [:class Foo:] the simple name is ''. For a
-   * constructor for [:class Foo:] named 'named' the simple name is 'named'.
-   * For a property [:foo:] the simple name of the getter method is 'foo' and
-   * the simple name of the setter is 'foo='. For operators the simple name is
-   * the operator itself, for example '+' for [:operator +:].
-   *
-   * The simple name for the unary minus operator is [Mirror.UNARY_MINUS].
-   */
-  String get simpleName;
-
-  /// Returns `true` if the name of this declaration is generated by the
-  /// provider of the mirror system.
-  bool get isNameSynthetic;
-
-  /**
-   * Returns the name of this entity qualified by is enclosing context. For
-   * instance, the qualified name of a method 'method' in class 'Class' in
-   * library 'library' is 'library.Class.method'.
-   */
-  String get qualifiedName;
-
-  /**
-   * The source location of this Dart language entity.
-   */
-  SourceLocation get location;
-
-  /**
-   * A mirror on the owner of this function. This is the declaration immediately
-   * surrounding the reflectee.
-   *
-   * Note that for libraries, the owner will be [:null:].
-   */
-  DeclarationMirror get owner;
-
-  /**
-   * Is this declaration private?
-   *
-   * Note that for libraries, this will be [:false:].
-   */
-  bool get isPrivate;
-
-  /**
-   * Is this declaration top-level?
-   *
-   * This is defined to be equivalent to:
-   *    [:mirror.owner != null && mirror.owner is LibraryMirror:]
-   */
-  bool get isTopLevel;
-
-  /**
-   * A list of the metadata associated with this declaration.
-   */
-  List<InstanceMirror> get metadata;
-
-  /**
-   * Looks up [name] in the scope of this declaration.
-   *
-   * [name] may be either a single identifier, like 'foo', or of the
-   * a prefixed identifier, like 'foo.bar', where 'foo' must be a prefix.
-   * For methods and constructors, the scope includes the parameters. For
-   * classes and typedefs, the scope includes the type variables.
-   * For classes and class members, the scope includes inherited members.
-   *
-   * See also:
-   *
-   * * [Lexical Scope](https://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#ch02-lexical-scope)
-   *   in Dart Up and Running.
-   * * [Lexical Scoping](http://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.jb82efuudrc5)
-   *   in the Dart Specification.
-   */
-  DeclarationMirror lookupInScope(String name);
-}
-
-abstract class ObjectMirror implements Mirror {
-  /**
-   * Invokes a getter and returns a mirror on the result. The getter
-   * can be the implicit getter for a field or a user-defined getter
-   * method.
-   */
-  InstanceMirror getField(String fieldName);
-}
-
-/**
- * An [InstanceMirror] reflects an instance of a Dart language object.
- */
-abstract class InstanceMirror implements ObjectMirror {
-  /**
-   * A mirror on the type of the reflectee.
-   */
-  ClassMirror get type;
-
-  /**
-   * Does [reflectee] contain the instance reflected by this mirror?
-   * This will always be true in the local case (reflecting instances
-   * in the same isolate), but only true in the remote case if this
-   * mirror reflects a simple value.
-   *
-   * A value is simple if one of the following holds:
-   *  - the value is null
-   *  - the value is of type [num]
-   *  - the value is of type [bool]
-   *  - the value is of type [String]
-   */
-  bool get hasReflectee;
-
-  /**
-   * If the [InstanceMirror] reflects an instance it is meaningful to
-   * have a local reference to, we provide access to the actual
-   * instance here.
-   *
-   * If you access [reflectee] when [hasReflectee] is false, an
-   * exception is thrown.
-   */
-  get reflectee;
-}
-
-/**
- * Specialized [InstanceMirror] used for reflection on constant lists.
- */
-abstract class ListInstanceMirror implements InstanceMirror {
-  /**
-   * Returns an instance mirror of the value at [index] or throws a [RangeError]
-   * if the [index] is out of bounds.
-   */
-  InstanceMirror operator[](int index);
-
-  /**
-   * The number of elements in the list.
-   */
-  int get length;
-}
-
-/**
- * Specialized [InstanceMirror] used for reflection on constant maps.
- */
-abstract class MapInstanceMirror implements InstanceMirror {
-  /**
-   * Returns a collection containing all the keys in the map.
-   */
-  Iterable<String> get keys;
-
-  /**
-   * Returns an instance mirror of the value for the given key or
-   * null if key is not in the map.
-   */
-  InstanceMirror operator[](String key);
-
-  /**
-   * The number of {key, value} pairs in the map.
-   */
-  int get length;
-}
-
-/**
- * Specialized [InstanceMirror] used for reflection on type constants.
- */
-abstract class TypeInstanceMirror implements InstanceMirror {
-  /**
-   * Returns the type mirror for the type represented by the reflected type
-   * constant.
-   */
-  TypeMirror get representedType;
-}
-
-/**
- * Specialized [InstanceMirror] used for reflection on comments as metadata.
- */
-abstract class CommentInstanceMirror implements InstanceMirror {
-  /**
-   * The comment text as written in the source text.
-   */
-  String get text;
-
-  /**
-   * The comment text without the start, end, and padding text.
-   *
-   * For example, if [text] is [: /** Comment text. */ :] then the [trimmedText]
-   * is [: Comment text. :].
-   */
-  String get trimmedText;
-
-  /**
-   * Is [:true:] if this comment is a documentation comment.
-   *
-   * That is, that the comment is either enclosed in [: /** ... */ :] or starts
-   * with [: /// :].
-   */
-  bool get isDocComment;
-}
-
-/**
- * Common interface for classes and libraries.
- */
-abstract class ContainerMirror implements Mirror {
-
-  /**
-   * An immutable map from from names to mirrors for all members in this
-   * container.
-   */
-  Map<String, MemberMirror> get members;
-}
-
-/**
- * A library.
- */
-abstract class LibraryMirror implements ContainerMirror, DeclarationMirror {
-  /**
-   * An immutable map from from names to mirrors for all members in this
-   * library.
-   *
-   * The members of a library are its top-level classes, functions, variables,
-   * getters, and setters.
-   */
-  Map<String, MemberMirror> get members;
-
-  /**
-   * An immutable map from names to mirrors for all class
-   * declarations in this library.
-   */
-  Map<String, ClassMirror> get classes;
-
-  /**
-   * An immutable map from names to mirrors for all function, getter,
-   * and setter declarations in this library.
-   */
-  Map<String, MethodMirror> get functions;
-
-  /**
-   * An immutable map from names to mirrors for all getter
-   * declarations in this library.
-   */
-  Map<String, MethodMirror> get getters;
-
-  /**
-   * An immutable map from names to mirrors for all setter
-   * declarations in this library.
-   */
-  Map<String, MethodMirror> get setters;
-
-  /**
-   * An immutable map from names to mirrors for all variable
-   * declarations in this library.
-   */
-  Map<String, VariableMirror> get variables;
-
-  /**
-   * Returns the canonical URI for this library.
-   */
-  Uri get uri;
-
-  /**
-   * Returns a list of the imports and exports in this library;
-   */
-  List<LibraryDependencyMirror> get libraryDependencies;
-}
-
-/// A mirror on an import or export declaration.
-abstract class LibraryDependencyMirror {
-  /// Is `true` if this dependency is an import.
-  bool get isImport;
-
-  /// Is `true` if this dependency is an export.
-  bool get isExport;
-
-  /// Returns the library mirror of the library that imports or exports the
-  /// [targetLibrary].
-  LibraryMirror get sourceLibrary;
-
-  /// Returns the library mirror of the library that is imported or exported.
-  LibraryMirror get targetLibrary;
-
-  /// Returns the prefix if this is a prefixed import and `null` otherwise.
-  String get prefix;
-
-  /// Returns the list of show/hide combinators on the import/export
-  /// declaration.
-  List<CombinatorMirror> get combinators;
-
-  /// Returns the source location for this import/export declaration.
-  SourceLocation get location;
-}
-
-/// A mirror on a show/hide combinator declared on a library dependency.
-abstract class CombinatorMirror {
-  /// The list of identifiers on the combinator.
-  List<String> get identifiers;
-
-  /// Is `true` if this is a 'show' combinator.
-  bool get isShow;
-
-  /// Is `true` if this is a 'hide' combinator.
-  bool get isHide;
-}
-
-/**
- * Common interface for classes, interfaces, typedefs and type variables.
- */
-abstract class TypeMirror implements DeclarationMirror {
-  /**
-   * Returns the library in which this member resides.
-   */
-  LibraryMirror get library;
-
-  /**
-   * Is [:true:] iff this type is the [:Object:] type.
-   */
-  bool get isObject;
-
-  /**
-   * Is [:true:] iff this type is the [:dynamic:] type.
-   */
-  bool get isDynamic;
-
-  /**
-   * Is [:true:] iff this type is the void type.
-   */
-  bool get isVoid;
-
-  /**
-   * Is [:true:] iff this type is a type variable.
-   */
-  bool get isTypeVariable;
-
-  /**
-   * Is [:true:] iff this type is a typedef.
-   */
-  bool get isTypedef;
-
-  /**
-   * Is [:true:] iff this type is a function type.
-   */
-  bool get isFunction;
-}
-
-/**
- * A class or interface type.
- */
-abstract class ClassMirror implements TypeMirror, ContainerMirror {
-  /**
-   * A mirror on the original declaration of this type.
-   *
-   * For most classes, they are their own original declaration.  For
-   * generic classes, however, there is a distinction between the
-   * original class declaration, which has unbound type variables, and
-   * the instantiations of generic classes, which have bound type
-   * variables.
-   */
-  ClassMirror get originalDeclaration;
-
-  /**
-   * Returns the super class of this type, or null if this type is [Object] or a
-   * typedef.
-   */
-  ClassMirror get superclass;
-
-  /**
-   * Returns a list of the interfaces directly implemented by this type.
-   */
-  List<ClassMirror> get superinterfaces;
-
-  /**
-   * The mixin of this class. If this class is the result of a mixin application
-   * of the form S with M, returns a class mirror on M. Otherwise return the
-   * class mirror itself.
-   */
-  ClassMirror get mixin;
-
-  /**
-   * Is [:true:] iff this type is a class.
-   */
-  bool get isClass;
-
-  /**
-   * Is this the original declaration of this type?
-   *
-   * For most classes, they are their own original declaration.  For
-   * generic classes, however, there is a distinction between the
-   * original class declaration, which has unbound type variables, and
-   * the instantiations of generic classes, which have bound type
-   * variables.
-   */
-  bool get isOriginalDeclaration;
-
-  /**
-   * Is [:true:] if this class is declared abstract.
-   */
-  bool get isAbstract;
-
-  /**
-   * Returns a list of the type arguments for this type.
-   */
-  List<TypeMirror> get typeArguments;
-
-  /**
-   * Returns the list of type variables for this type.
-   */
-  List<TypeVariableMirror> get typeVariables;
-
-  /**
-   * An immutable map from from names to mirrors for all members of
-   * this type.
-   *
-   * The members of a type are its methods, fields, getters, and
-   * setters.  Note that constructors and type variables are not
-   * considered to be members of a type.
-   *
-   * This does not include inherited members.
-   */
-  Map<String, MemberMirror> get members;
-
-  /**
-   * An immutable map from names to mirrors for all method,
-   * declarations for this type.  This does not include getters and
-   * setters.
-   */
-  Map<String, MethodMirror> get methods;
-
-  /**
-   * An immutable map from names to mirrors for all getter
-   * declarations for this type.
-   */
-  Map<String, MethodMirror> get getters;
-
-  /**
-   * An immutable map from names to mirrors for all setter
-   * declarations for this type.
-   */
-  Map<String, MethodMirror> get setters;
-
-  /**
-   * An immutable map from names to mirrors for all variable
-   * declarations for this type.
-   */
-  Map<String, VariableMirror> get variables;
-
-  /**
-   * An immutable map from names to mirrors for all constructor
-   * declarations for this type.
-   */
-  Map<String, MethodMirror> get constructors;
-}
-
-/**
- * A type parameter as declared on a generic type.
- */
-abstract class TypeVariableMirror implements TypeMirror {
-  /**
-   * Returns the bound of the type parameter.
-   */
-  TypeMirror get upperBound;
-}
-
-/**
- * A function type.
- */
-abstract class FunctionTypeMirror implements ClassMirror {
-  /**
-   * Returns the return type of this function type.
-   */
-  TypeMirror get returnType;
-
-  /**
-   * Returns the parameters for this function type.
-   */
-  List<ParameterMirror> get parameters;
-
-  /**
-   * Returns the call method for this function type.
-   */
-  MethodMirror get callMethod;
-}
-
-/**
- * A typedef.
- */
-abstract class TypedefMirror implements ClassMirror {
-  /**
-   * The defining type for this typedef.
-   *
-   * For instance [:void f(int):] for a [:typedef void f(int):].
-   */
-  TypeMirror get value;
-}
-
-/**
- * A member of a type, i.e. a field, method or constructor.
- */
-abstract class MemberMirror implements DeclarationMirror {
-  /**
-   * Is this member a constructor?
-   */
-  bool get isConstructor;
-
-  /**
-   * Is this member a variable?
-   *
-   * This is [:false:] for locals.
-   */
-  bool get isVariable;
-
-  /**
-   * Is this member a method?.
-   *
-   * This is [:false:] for constructors.
-   */
-  bool get isMethod;
-
-  /**
-   * Is this member declared static?
-   */
-  bool get isStatic;
-
-  /**
-   * Is this member a parameter?
-   */
-  bool get isParameter;
-}
-
-/**
- * A field.
- */
-abstract class VariableMirror implements MemberMirror {
-
-  /**
-   * Returns true if this field is final.
-   */
-  bool get isFinal;
-
-  /**
-   * Returns true if this field is const.
-   */
-  bool get isConst;
-
-  /**
-   * Returns the type of this field.
-   */
-  TypeMirror get type;
-}
-
-/**
- * Common interface constructors and methods, including factories, getters and
- * setters.
- */
-abstract class MethodMirror implements MemberMirror {
-  /**
-   * Returns the list of parameters for this method.
-   */
-  List<ParameterMirror> get parameters;
-
-  /**
-   * Returns the return type of this method.
-   */
-  TypeMirror get returnType;
-
-  /**
-   * Is the reflectee abstract?
-   */
-  bool get isAbstract;
-
-  /**
-   * Is the reflectee a regular function or method?
-   *
-   * A function or method is regular if it is not a getter, setter, or
-   * constructor.  Note that operators, by this definition, are
-   * regular methods.
-   */
-  bool get isRegularMethod;
-
-  /**
-   * Is the reflectee a const constructor?
-   */
-  bool get isConstConstructor;
-
-  /**
-   * Is the reflectee a generative constructor?
-   */
-  bool get isGenerativeConstructor;
-
-  /**
-   * Is the reflectee a redirecting constructor?
-   */
-  bool get isRedirectingConstructor;
-
-  /**
-   * Is the reflectee a factory constructor?
-   */
-  bool get isFactoryConstructor;
-
-  /**
-   * Is [:true:] if this method is a getter method.
-   */
-  bool get isGetter;
-
-  /**
-   * Is [:true:] if this method is a setter method.
-   */
-  bool get isSetter;
-
-  /**
-   * Is [:true:] if this method is an operator method.
-   */
-  bool get isOperator;
-}
-
-/**
- * A formal parameter.
- */
-abstract class ParameterMirror implements VariableMirror {
-  /**
-   * Returns the type of this parameter.
-   */
-  TypeMirror get type;
-
-  /**
-   * Returns the default value for this parameter.
-   */
-  String get defaultValue;
-
-  /**
-   * Does this parameter have a default value?
-   */
-  bool get hasDefaultValue;
-
-  /**
-   * Is this parameter optional?
-   */
-  bool get isOptional;
-
-  /**
-   * Is this parameter named?
-   */
-  bool get isNamed;
-
-  /**
-   * Returns [:true:] iff this parameter is an initializing formal of a
-   * constructor. That is, if it is of the form [:this.x:] where [:x:] is a
-   * field.
-   */
-  bool get isInitializingFormal;
-
-  /**
-   * Returns the initialized field, if this parameter is an initializing formal.
-   */
-  VariableMirror get initializedField;
-}
-
-/**
- * A [SourceLocation] describes the span of an entity in Dart source code.
- * A [SourceLocation] with a non-zero [length] should be the minimum span that
- * encloses the declaration of the mirrored entity.
- */
-abstract class SourceLocation {
-  /**
-   * The 1-based line number for this source location.
-   *
-   * A value of 0 means that the line number is unknown.
-   */
-  int get line;
-
-  /**
-   * The 1-based column number for this source location.
-   *
-   * A value of 0 means that the column number is unknown.
-   */
-  int get column;
-
-  /**
-   * The 0-based character offset into the [sourceText] where this source
-   * location begins.
-   *
-   * A value of -1 means that the offset is unknown.
-   */
-  int get offset;
-
-  /**
-   * The number of characters in this source location.
-   *
-   * A value of 0 means that the [offset] is approximate.
-   */
-  int get length;
-
-  /**
-   * The text of the location span.
-   */
-  String get text;
-
-  /**
-   * Returns the URI where the source originated.
-   */
-  Uri get sourceUri;
-
-  /**
-   * Returns the text of this source.
-   */
-  String get sourceText;
-}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart
index 1c7323f..fca92c4 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart
@@ -6,13 +6,20 @@
 
 import 'dart:collection' show Queue, IterableBase;
 
-// TODO(rnystrom): Use "package:" URL (#4968).
-import 'mirrors.dart';
+import 'source_mirrors.dart';
 
 //------------------------------------------------------------------------------
 // Utility functions for using the Mirror API
 //------------------------------------------------------------------------------
 
+String nameOf(DeclarationMirror mirror) =>
+    MirrorSystem.getName(mirror.simpleName);
+
+String qualifiedNameOf(DeclarationMirror mirror) =>
+    MirrorSystem.getName(mirror.qualifiedName);
+
+// TODO(johnniwinther): Handle private names.
+Symbol symbolOf(String name, [LibraryMirror library]) => new Symbol(name);
 
 /**
  * Return the display name for [mirror].
@@ -32,15 +39,14 @@
       return library.uri.toString();
     }
   } else if (mirror is MethodMirror) {
-    MethodMirror methodMirror = mirror;
-    String simpleName = methodMirror.simpleName;
-    if (methodMirror.isSetter) {
+    String simpleName = nameOf(mirror);
+    if (mirror.isSetter) {
       // Remove trailing '='.
       return simpleName.substring(0, simpleName.length-1);
-    } else if (methodMirror.isOperator) {
-      return 'operator ${operatorName(methodMirror)}';
-    } else if (methodMirror.isConstructor) {
-      String className = displayName(methodMirror.owner);
+    } else if (mirror.isOperator) {
+      return 'operator ${operatorName(mirror)}';
+    } else if (mirror.isConstructor) {
+      String className = displayName(mirror.owner);
       if (simpleName == '') {
         return className;
       } else {
@@ -48,7 +54,7 @@
       }
     }
   }
-  return mirror.simpleName;
+  return MirrorSystem.getName(mirror.simpleName);
 }
 
 /**
@@ -57,12 +63,11 @@
  * operator. Return [:null:] if [methodMirror] is not an operator method.
  */
 String operatorName(MethodMirror methodMirror) {
-  String simpleName = methodMirror.simpleName;
   if (methodMirror.isOperator) {
-    if (simpleName == Mirror.UNARY_MINUS) {
+    if (methodMirror.simpleName == const Symbol('unary-')) {
       return '-';
     } else {
-      return simpleName;
+      return nameOf(methodMirror);
     }
   }
   return null;
@@ -70,47 +75,35 @@
 
 /**
  * Returns an iterable over the type declarations directly inheriting from
- * the declaration of this type.
+ * the declaration of [type] within [mirrors].
  */
-Iterable<ClassMirror> computeSubdeclarations(ClassMirror type) {
+Iterable<ClassMirror> computeSubdeclarations(MirrorSystem mirrors,
+                                             ClassMirror type) {
   type = type.originalDeclaration;
   var subtypes = <ClassMirror>[];
-  type.mirrors.libraries.forEach((_, library) {
-    for (ClassMirror otherType in library.classes.values) {
+  mirrors.libraries.forEach((_, library) {
+    library.declarations.values
+        .where((mirror) => mirror is ClassMirror)
+        .forEach((ClassMirror otherType) {
       var superClass = otherType.superclass;
       if (superClass != null) {
         superClass = superClass.originalDeclaration;
-        if (type.library == superClass.library) {
-          if (superClass == type) {
-             subtypes.add(otherType);
-          }
+        if (superClass == type) {
+          subtypes.add(otherType);
         }
       }
       final superInterfaces = otherType.superinterfaces;
       for (ClassMirror superInterface in superInterfaces) {
         superInterface = superInterface.originalDeclaration;
-        if (type.library == superInterface.library) {
-          if (superInterface == type) {
-            subtypes.add(otherType);
-          }
+        if (superInterface == type) {
+          subtypes.add(otherType);
         }
       }
-    }
+    });
   });
   return subtypes;
 }
 
-LibraryMirror findLibrary(MemberMirror member) {
-  DeclarationMirror owner = member.owner;
-  if (owner is LibraryMirror) {
-    return owner;
-  } else if (owner is TypeMirror) {
-    TypeMirror mirror = owner;
-    return mirror.library;
-  }
-  throw new Exception('Unexpected owner: ${owner}');
-}
-
 class HierarchyIterable extends IterableBase<ClassMirror> {
   final bool includeType;
   final ClassMirror type;
@@ -146,7 +139,7 @@
 
   ClassMirror push(ClassMirror type) {
     if (type.superclass != null) {
-      if (type.superclass.isObject) {
+      if (isObject(type.superclass)) {
         object = type.superclass;
       } else {
         queue.addFirst(type.superclass);
@@ -172,10 +165,67 @@
   }
 }
 
+LibraryMirror getLibrary(DeclarationMirror declaration) {
+  while (declaration != null && declaration is! LibraryMirror) {
+    declaration = declaration.owner;
+  }
+  return declaration;
+}
+
+Iterable<DeclarationMirror> membersOf(
+    Map<Symbol, DeclarationMirror> declarations) {
+  return declarations.values.where(
+      (mirror) => mirror is MethodMirror || mirror is VariableMirror);
+}
+
+Iterable<TypeMirror> classesOf(
+    Map<Symbol, DeclarationMirror> declarations) {
+  return declarations.values.where((mirror) => mirror is ClassMirror);
+}
+
+Iterable<TypeMirror> typesOf(
+    Map<Symbol, DeclarationMirror> declarations) {
+  return declarations.values.where((mirror) => mirror is TypeMirror);
+}
+
+Iterable<MethodMirror> methodsOf(
+    Map<Symbol, DeclarationMirror> declarations) {
+  return declarations.values.where(
+      (mirror) => mirror is MethodMirror && mirror.isRegularMethod);
+}
+
+Iterable<MethodMirror> constructorsOf(
+    Map<Symbol, DeclarationMirror> declarations) {
+  return declarations.values.where(
+      (mirror) => mirror is MethodMirror && mirror.isConstructor);
+}
+
+Iterable<MethodMirror> settersOf(
+    Map<Symbol, DeclarationMirror> declarations) {
+  return declarations.values.where(
+      (mirror) => mirror is MethodMirror && mirror.isSetter);
+}
+
+Iterable<MethodMirror> gettersOf(
+    Map<Symbol, DeclarationMirror> declarations) {
+  return declarations.values.where(
+      (mirror) => mirror is MethodMirror && mirror.isGetter);
+}
+
+Iterable<VariableMirror> variablesOf(
+    Map<Symbol, DeclarationMirror> declarations) {
+  return declarations.values.where((mirror) => mirror is VariableMirror);
+}
+
+
+
+bool isObject(TypeMirror mirror) =>
+    mirror is ClassMirror && mirror.superclass == null;
+
 /// Returns `true` if [cls] is declared in a private dart library.
 bool isFromPrivateDartLibrary(ClassMirror cls) {
   if (isMixinApplication(cls)) cls = cls.mixin;
-  var uri = cls.library.uri;
+  var uri = getLibrary(cls).uri;
   return uri.scheme == 'dart' && uri.path.startsWith('_');
 }
 
@@ -196,8 +246,8 @@
  *     class A = B with C1, C2;
  *     abstract class A = B with C1, C2 implements D1, D2;
  */
-ClassMirror getSuperclass(ClassMirror cls) {
-  ClassMirror superclass = cls.superclass;
+ClassSourceMirror getSuperclass(ClassSourceMirror cls) {
+  ClassSourceMirror superclass = cls.superclass;
   while (isMixinApplication(superclass) && superclass.isNameSynthetic) {
     superclass = superclass.superclass;
   }
@@ -215,15 +265,15 @@
  *     class A = B with C1, C2;
  *     abstract class A = B with C1, C2 implements D1, D2;
  */
-Iterable<ClassMirror> getAppliedMixins(ClassMirror cls) {
-  List<ClassMirror> mixins = <ClassMirror>[];
-  ClassMirror superclass = cls.superclass;
+Iterable<ClassSourceMirror> getAppliedMixins(ClassSourceMirror cls) {
+  List<ClassSourceMirror> mixins = <ClassSourceMirror>[];
+  ClassSourceMirror superclass = cls.superclass;
   while (isMixinApplication(superclass) && superclass.isNameSynthetic) {
     mixins.add(superclass.mixin);
     superclass = superclass.superclass;
   }
   if (mixins.length > 1) {
-    mixins = new List<ClassMirror>.from(mixins.reversed);
+    mixins = new List<ClassSourceMirror>.from(mixins.reversed);
   }
   if (isMixinApplication(cls)) {
     mixins.add(cls.mixin);
@@ -314,7 +364,7 @@
  * variable of [:Iterable:] and 'col.Iterable.contains.element' finds the
  * [:element:] parameter of the [:contains:] method on [:Iterable:].
  */
-DeclarationMirror lookupQualifiedInScope(DeclarationMirror declaration,
+DeclarationMirror lookupQualifiedInScope(DeclarationSourceMirror declaration,
                                          String name) {
   // TODO(11653): Support lookup of constructors using the [:new Foo:]
   // syntax.
@@ -327,28 +377,27 @@
     offset = 2;
   }
   if (result == null) return null;
+  LibraryMirror library = getLibrary(result);
   while (result != null && offset < parts.length) {
-    result = _lookupLocal(result, parts[offset++]);
+    result = _lookupLocal(result, symbolOf(parts[offset++], library));
   }
   return result;
 }
 
-DeclarationMirror _lookupLocal(Mirror mirror, String id) {
+DeclarationMirror _lookupLocal(Mirror mirror, Symbol id) {
   DeclarationMirror result;
-  if (mirror is ContainerMirror) {
-    ContainerMirror containerMirror = mirror;
+  if (mirror is LibraryMirror) {
     // Try member lookup.
-    result = containerMirror.members[id];
-  }
-  if (result != null) return result;
-  if (mirror is ClassMirror) {
-    ClassMirror classMirror = mirror;
+    result = mirror.declarations[id];
+  } else if (mirror is ClassMirror) {
+    // Try member lookup.
+    result = mirror.declarations[id];
+    if (result != null) return result;
     // Try type variables.
-    result = classMirror.typeVariables.firstWhere(
+    result = mirror.typeVariables.firstWhere(
         (TypeVariableMirror v) => v.simpleName == id, orElse: () => null);
   } else if (mirror is MethodMirror) {
-    MethodMirror methodMirror = mirror;
-    result = methodMirror.parameters.firstWhere(
+    result = mirror.parameters.firstWhere(
         (ParameterMirror p) => p.simpleName == id, orElse: () => null);
   }
   return result;
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart b/sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart
new file mode 100644
index 0000000..1a80852
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart
@@ -0,0 +1,249 @@
+// Copyright (c) 2012, 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.
+
+library mirrors;
+
+import 'dart:mirrors';
+import 'dart:mirrors' as api show SourceLocation;
+export 'dart:mirrors';
+
+abstract class DeclarationSourceMirror implements DeclarationMirror {
+  /// Returns `true` if the name of this declaration is generated by the
+  /// provider of the mirror system.
+  bool get isNameSynthetic;
+
+  /**
+   * Looks up [name] in the scope of this declaration.
+   *
+   * [name] may be either a single identifier, like 'foo', or of the
+   * a prefixed identifier, like 'foo.bar', where 'foo' must be a prefix.
+   * For methods and constructors, the scope includes the parameters. For
+   * classes and typedefs, the scope includes the type variables.
+   * For classes and class members, the scope includes inherited members.
+   *
+   * See also:
+   *
+   * * [Lexical Scope](https://www.dartlang.org/docs/dart-up-and-running/contents/ch02.html#ch02-lexical-scope)
+   *   in Dart Up and Running.
+   * * [Lexical Scoping](http://www.dartlang.org/docs/spec/latest/dart-language-specification.html#h.jb82efuudrc5)
+   *   in the Dart Specification.
+   */
+  DeclarationMirror lookupInScope(String name);
+}
+
+/**
+ * Specialized [InstanceMirror] used for reflection on constant lists.
+ */
+abstract class ListInstanceMirror implements InstanceMirror {
+  /**
+   * Returns an instance mirror of the value at [index] or throws a [RangeError]
+   * if the [index] is out of bounds.
+   */
+  InstanceMirror getElement(int index);
+
+  /**
+   * The number of elements in the list.
+   */
+  int get length;
+}
+
+/**
+ * Specialized [InstanceMirror] used for reflection on constant maps.
+ */
+abstract class MapInstanceMirror implements InstanceMirror {
+  /**
+   * Returns a collection containing all the keys in the map.
+   */
+  Iterable<String> get keys;
+
+  /**
+   * Returns an instance mirror of the value for the given key or
+   * null if key is not in the map.
+   */
+  InstanceMirror getValue(String key);
+
+  /**
+   * The number of {key, value} pairs in the map.
+   */
+  int get length;
+}
+
+/**
+ * Specialized [InstanceMirror] used for reflection on type constants.
+ */
+abstract class TypeInstanceMirror implements InstanceMirror {
+  /**
+   * Returns the type mirror for the type represented by the reflected type
+   * constant.
+   */
+  TypeMirror get representedType;
+}
+
+/**
+ * Specialized [InstanceMirror] used for reflection on comments as metadata.
+ */
+abstract class CommentInstanceMirror implements InstanceMirror {
+  /**
+   * The comment text as written in the source text.
+   */
+  String get text;
+
+  /**
+   * The comment text without the start, end, and padding text.
+   *
+   * For example, if [text] is [: /** Comment text. */ :] then the [trimmedText]
+   * is [: Comment text. :].
+   */
+  String get trimmedText;
+
+  /**
+   * Is [:true:] if this comment is a documentation comment.
+   *
+   * That is, that the comment is either enclosed in [: /** ... */ :] or starts
+   * with [: /// :].
+   */
+  bool get isDocComment;
+}
+
+/**
+ * A library.
+ */
+abstract class LibrarySourceMirror
+    implements DeclarationSourceMirror, LibraryMirror {
+  /**
+   * Returns a list of the imports and exports in this library;
+   */
+  List<LibraryDependencyMirror> get libraryDependencies;
+}
+
+/// A mirror on an import or export declaration.
+abstract class LibraryDependencyMirror extends Mirror {
+  /// Is `true` if this dependency is an import.
+  bool get isImport;
+
+  /// Is `true` if this dependency is an export.
+  bool get isExport;
+
+  /// Returns the library mirror of the library that imports or exports the
+  /// [targetLibrary].
+  LibraryMirror get sourceLibrary;
+
+  /// Returns the library mirror of the library that is imported or exported.
+  LibraryMirror get targetLibrary;
+
+  /// Returns the prefix if this is a prefixed import and `null` otherwise.
+  String get prefix;
+
+  /// Returns the list of show/hide combinators on the import/export
+  /// declaration.
+  List<CombinatorMirror> get combinators;
+
+  /// Returns the source location for this import/export declaration.
+  SourceLocation get location;
+}
+
+/// A mirror on a show/hide combinator declared on a library dependency.
+abstract class CombinatorMirror extends Mirror {
+  /// The list of identifiers on the combinator.
+  List<String> get identifiers;
+
+  /// Is `true` if this is a 'show' combinator.
+  bool get isShow;
+
+  /// Is `true` if this is a 'hide' combinator.
+  bool get isHide;
+}
+
+/**
+ * Common interface for classes, interfaces, typedefs and type variables.
+ */
+abstract class TypeSourceMirror implements DeclarationSourceMirror, TypeMirror {
+  /// Returns `true` is this is a mirror on the void type.
+  bool get isVoid;
+
+  /// Returns `true` is this is a mirror on the dynamic type.
+  bool get isDynamic;
+
+  /// Create a type mirror on the instantiation of the declaration of this type
+  /// with [typeArguments] as type arguments.
+  TypeMirror createInstantiation(List<TypeMirror> typeArguments);
+}
+
+/**
+ * A class or interface type.
+ */
+abstract class ClassSourceMirror implements TypeSourceMirror, ClassMirror {
+  /**
+   * Is [:true:] if this class is declared abstract.
+   */
+  bool get isAbstract;
+}
+
+/**
+ * A formal parameter.
+ */
+abstract class ParameterSourceMirror implements ParameterMirror {
+  /**
+   * Returns [:true:] iff this parameter is an initializing formal of a
+   * constructor. That is, if it is of the form [:this.x:] where [:x:] is a
+   * field.
+   */
+  bool get isInitializingFormal;
+
+  /**
+   * Returns the initialized field, if this parameter is an initializing formal.
+   */
+  VariableMirror get initializedField;
+}
+
+/**
+ * A [SourceLocation] describes the span of an entity in Dart source code.
+ * A [SourceLocation] with a non-zero [length] should be the minimum span that
+ * encloses the declaration of the mirrored entity.
+ */
+abstract class SourceLocation implements api.SourceLocation {
+  /**
+   * The 1-based line number for this source location.
+   *
+   * A value of 0 means that the line number is unknown.
+   */
+  int get line;
+
+  /**
+   * The 1-based column number for this source location.
+   *
+   * A value of 0 means that the column number is unknown.
+   */
+  int get column;
+
+  /**
+   * The 0-based character offset into the [sourceText] where this source
+   * location begins.
+   *
+   * A value of -1 means that the offset is unknown.
+   */
+  int get offset;
+
+  /**
+   * The number of characters in this source location.
+   *
+   * A value of 0 means that the [offset] is approximate.
+   */
+  int get length;
+
+  /**
+   * The text of the location span.
+   */
+  String get text;
+
+  /**
+   * Returns the URI where the source originated.
+   */
+  Uri get sourceUri;
+
+  /**
+   * Returns the text of this source.
+   */
+  String get sourceText;
+}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/util.dart b/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
index db94f02..7d9ad77 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/util.dart
@@ -2,7 +2,9 @@
 // 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.
 
-library util;
+library dart2js.mirrors.util;
+
+import 'dart:collection' show Maps;
 
 /**
  * An abstract map implementation. This class can be used as a superclass for
@@ -24,7 +26,7 @@
   void clear() {
     throw new UnsupportedError('clear() is not supported');
   }
-  
+
   void addAll(Map<K, V> other) {
     throw new UnsupportedError('addAll() is not supported');
   }
@@ -75,6 +77,8 @@
   V remove(K key) {
     throw new UnsupportedError('V remove(K key) is not supported');
   }
+
+  String toString() => Maps.mapToString(this);
 }
 
 /**
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 06430af..ea8ba1e 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -385,6 +385,8 @@
 
   PatchMetadataAnnotation() : super(STATE_DONE);
 
+  tree.Node parseNode(leg.DiagnosticListener listener) => null;
+
   Token get beginToken => null;
   Token get endToken => null;
 }
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index af629c4..8f75bf1 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -326,8 +326,20 @@
                                     Link<Element> originParameters,
                                     Link<Element> patchParameters) {
     while (!originParameters.isEmpty) {
-      Element originParameter = originParameters.head;
-      Element patchParameter = patchParameters.head;
+      VariableElementX originParameter = originParameters.head;
+      VariableElementX patchParameter = patchParameters.head;
+      // TODO(johnniwinther): Remove the case for reassignment of
+      // [patch]/[origin] when resolution is ensure to be done only once.
+      assert(invariant(originParameter, originParameter.origin == null));
+      assert(invariant(originParameter,
+          originParameter.patch == null ||
+          originParameter.patch == patchParameter));
+      originParameter.patch = patchParameter;
+      assert(invariant(patchParameter,
+          patchParameter.origin == null ||
+          patchParameter.origin == originParameter));
+      assert(invariant(patchParameter, patchParameter.patch == null));
+      patchParameter.origin = originParameter;
       // Hack: Use unparser to test parameter equality. This only works because
       // we are restricting patch uses and the approach cannot be used
       // elsewhere.
@@ -1196,7 +1208,7 @@
         namedParameterTypes);
   }
 
-  void resolveMetadataAnnotation(PartialMetadataAnnotation annotation) {
+  void resolveMetadataAnnotation(MetadataAnnotationX annotation) {
     compiler.withCurrentElement(annotation.annotatedElement, () => measure(() {
       assert(annotation.resolutionState == STATE_NOT_STARTED);
       annotation.resolutionState = STATE_STARTED;
@@ -2959,14 +2971,15 @@
     VariableDefinitionsVisitor visitor =
         new VariableDefinitionsVisitor(compiler, node, this,
                                        ElementKind.VARIABLE);
+    VariableListElement variables = visitor.variables;
     // Ensure that we set the type of the [VariableListElement] since it depends
     // on the current scope. If the current scope is a [MethodScope] or
     // [BlockScope] it will not be available for the
     // [VariableListElement.computeType] method.
     if (node.type != null) {
-      visitor.variables.type = resolveTypeAnnotation(node.type);
+      variables.type = resolveTypeAnnotation(node.type);
     } else {
-      visitor.variables.type = compiler.types.dynamicType;
+      variables.type = compiler.types.dynamicType;
     }
 
     Modifiers modifiers = node.modifiers;
@@ -2998,6 +3011,17 @@
         reportExtraModifier('static');
       }
     }
+    if (node.metadata != null) {
+      // TODO(johnniwinther): Unify handling of metadata on locals/formals.
+      for (Link<Node> link = node.metadata.nodes;
+           !link.isEmpty;
+           link = link.tail) {
+        ParameterMetadataAnnotation metadata =
+            new ParameterMetadataAnnotation(link.head);
+        variables.addMetadata(metadata);
+        metadata.ensureResolved(compiler);
+      }
+    }
     visitor.visit(node.definitions);
   }
 
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
index 3499562..460f6da 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/resolution.dart
@@ -24,9 +24,10 @@
          MixinApplicationElementX,
          TypeVariableElementX,
          TypedefElementX,
-         SynthesizedConstructorElementX;
+         SynthesizedConstructorElementX,
+         MetadataAnnotationX,
+         ParameterMetadataAnnotation;
 import '../util/util.dart';
-import '../scanner/scannerlib.dart' show PartialMetadataAnnotation;
 
 import 'secret_tree_element.dart' show getTreeElement, setTreeElement;
 import '../ordered_typeset.dart' show OrderedTypeSet, OrderedTypeSetBuilder;
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart b/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
index c2aab56..5e7c834 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/signatures.dart
@@ -63,6 +63,17 @@
     }
     currentDefinitions = node;
     Element element = definition.accept(this);
+    if (currentDefinitions.metadata != null) {
+      // TODO(johnniwinther): Unify handling of metadata on locals/formals.
+      for (Link<Node> link = currentDefinitions.metadata.nodes;
+           !link.isEmpty;
+           link = link.tail) {
+        ParameterMetadataAnnotation metadata =
+            new ParameterMetadataAnnotation(link.head);
+        element.addMetadata(metadata);
+        metadata.ensureResolved(compiler);
+      }
+    }
     currentDefinitions = null;
     return element;
   }
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
index 1d17df3..1cfc71c 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
@@ -43,7 +43,8 @@
         Token token = parser.parseTopLevelDeclaration(beginToken);
         assert(identical(token, endToken.next));
         cachedNode = listener.popNode();
-        assert(listener.nodes.isEmpty);
+        assert(invariant(beginToken, listener.nodes.isEmpty,
+            message: "Non-empty listener stack: ${listener.nodes}"));
       });
       compiler.patchParser.measure(() {
         if (isPatched) {
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index 1be0e2a..67fc779 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -252,6 +252,12 @@
   void endMethod(Token getOrSet, Token beginToken, Token endToken) {
   }
 
+  void beginMetadataStar(Token token) {
+  }
+
+  void endMetadataStar(int count, bool forParameter) {
+  }
+
   void beginMetadata(Token token) {
   }
 
@@ -1264,8 +1270,9 @@
     }
     TypeAnnotation type = popNode();
     Modifiers modifiers = popNode();
-    pushNode(
-        new VariableDefinitions(type, modifiers, new NodeList.singleton(name)));
+    NodeList metadata = popNode();
+    pushNode(new VariableDefinitions.forParameter(
+        metadata, type, modifiers, new NodeList.singleton(name)));
   }
 
   void endFormalParameters(int count, Token beginToken, Token endToken) {
@@ -1812,6 +1819,17 @@
                                 beginToken, inKeyword));
   }
 
+  void endMetadataStar(int count, bool forParameter) {
+    // TODO(johnniwinther): Handle metadata for all node kinds.
+    if (forParameter) {
+      if (0 == count) {
+        pushNode(null);
+      } else {
+        pushNode(makeNodeList(count, null, null, ' '));
+      }
+    }
+  }
+
   void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
     NodeList arguments = popNode();
     if (arguments == null) {
@@ -1839,13 +1857,14 @@
       if (name != null) {
         send = new Send(receiver, name);
       }
-      pushNode(send);
+      pushNode(new Metadata(beginToken, send));
     } else {
       // This is a const constructor call.
       endConstructorReference(beginToken, periodBeforeName, endToken);
       Node constructor = popNode();
-      pushNode(new NewExpression(beginToken,
-                                 new Send(null, constructor, arguments)));
+      pushNode(new Metadata(beginToken,
+          new NewExpression(null,
+              new Send(null, constructor, arguments))));
     }
   }
 
@@ -1993,7 +2012,6 @@
   final Token beginToken;
   final Token tokenAfterEndToken;
   Expression cachedNode;
-  Constant value;
 
   PartialMetadataAnnotation(this.beginToken, this.tokenAfterEndToken);
 
@@ -2007,9 +2025,10 @@
 
   Node parseNode(DiagnosticListener listener) {
     if (cachedNode != null) return cachedNode;
-    cachedNode = parse(listener,
-                       annotatedElement.getCompilationUnit(),
-                       (p) => p.parseMetadata(beginToken));
+    Metadata metadata = parse(listener,
+                              annotatedElement.getCompilationUnit(),
+                              (p) => p.parseMetadata(beginToken));
+    cachedNode = metadata.expression;
     return cachedNode;
   }
 }
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index 53f04db..365a92b 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -215,10 +215,14 @@
     return token;
   }
 
-  Token parseMetadataStar(Token token) {
+  Token parseMetadataStar(Token token, {bool forParameter: false}) {
+    listener.beginMetadataStar(token);
+    int count = 0;
     while (optional('@', token)) {
       token = parseMetadata(token);
+      count++;
     }
+    listener.endMetadataStar(count, forParameter);
     return token;
   }
 
@@ -326,6 +330,7 @@
   }
 
   Token parseFormalParameter(Token token, FormalParameterType type) {
+    token = parseMetadataStar(token, forParameter: true);
     listener.beginFormalParameter(token);
     token = parseModifiers(token);
     // TODO(ahe): Validate that there are formal parameters if void.
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index cd96172..8116646 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -1706,14 +1706,22 @@
   MemorySet(this.compiler);
 
   /**
-   * Returns whether [first] and [second] may alias to the same
-   * object.
+   * Returns whether [first] and [second] always alias to the same object.
+   */
+  bool mustAlias(HInstruction first, HInstruction second) {
+    return first == second;
+  }
+
+  /**
+   * Returns whether [first] and [second] may alias to the same object.
    */
   bool mayAlias(HInstruction first, HInstruction second) {
-    if (first == second) return true;
+    if (mustAlias(first, second)) return true;
     if (isConcrete(first) && isConcrete(second)) return false;
     if (nonEscapingReceivers.contains(first)) return false;
     if (nonEscapingReceivers.contains(second)) return false;
+    // Typed arrays of different types might have a shared buffer.
+    if (couldBeTypedArray(first) && couldBeTypedArray(second)) return true;
     TypeMask intersection = first.instructionType.intersection(
         second.instructionType, compiler);
     if (intersection.isEmpty) return false;
@@ -1730,6 +1738,11 @@
         || instruction is HLiteralList;
   }
 
+  bool couldBeTypedArray(HInstruction receiver) {
+    JavaScriptBackend backend = compiler.backend;
+    return backend.couldBeTypedArray(receiver.instructionType);
+  }
+
   /**
    * Returns whether [receiver] escapes the current function.
    */
@@ -1849,15 +1862,19 @@
     nonEscapingReceivers.remove(value);
     keyedValues.forEach((key, values) {
       if (mayAlias(receiver, key)) {
+        // Typed arrays that are views of the same buffer may have different
+        // offsets or element sizes, unless they are the same typed array.
+        bool weakIndex = couldBeTypedArray(key) && !mustAlias(receiver, key);
         values.forEach((otherIndex, otherValue) {
-          if (mayAlias(index, otherIndex)) values[otherIndex] = null;
+          if (weakIndex || mayAlias(index, otherIndex)) {
+            values[otherIndex] = null;
+          }
         });
       }
     });
 
-    JavaScriptBackend backend = compiler.backend;
     // Typed arrays may narrow incoming values.
-    if (backend.couldBeTypedArray(receiver.instructionType)) return;
+    if (couldBeTypedArray(receiver)) return;
 
     Map<HInstruction, HInstruction> map = keyedValues.putIfAbsent(
         receiver, () => <HInstruction, HInstruction> {});
diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
index e64cbf6..80f0b13 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
@@ -48,6 +48,7 @@
   R visitLiteralString(LiteralString node) => visitStringNode(node);
   R visitStringJuxtaposition(StringJuxtaposition node) => visitStringNode(node);
   R visitLoop(Loop node) => visitStatement(node);
+  R visitMetadata(Metadata node) => visitNode(node);
   R visitMixinApplication(MixinApplication node) => visitNode(node);
   R visitModifiers(Modifiers node) => visitNode(node);
   R visitNamedArgument(NamedArgument node) => visitExpression(node);
@@ -173,6 +174,7 @@
   LiteralNull asLiteralNull() => null;
   LiteralString asLiteralString() => null;
   LiteralSymbol asLiteralSymbol() => null;
+  Metadata asMetadata() => null;
   MixinApplication asMixinApplication() => null;
   Modifiers asModifiers() => null;
   NamedArgument asNamedArgument() => null;
@@ -479,7 +481,7 @@
 }
 
 class NewExpression extends Expression {
-  /** The token NEW or CONST */
+  /** The token NEW or CONST or `null` for metadata */
   final Token newToken;
 
   // Note: we expect that send.receiver is null.
@@ -496,11 +498,10 @@
   }
 
   bool isConst() {
-    return identical(newToken.stringValue, 'const')
-        || identical(newToken.stringValue, '@');
+    return newToken == null || identical(newToken.stringValue, 'const');
   }
 
-  Token getBeginToken() => newToken;
+  Token getBeginToken() => newToken != null ? newToken : send.getBeginToken();
 
   Token getEndToken() => send.getEndToken();
 }
@@ -1136,10 +1137,23 @@
 }
 
 class VariableDefinitions extends Statement {
+  final NodeList metadata;
   final TypeAnnotation type;
   final Modifiers modifiers;
   final NodeList definitions;
-  VariableDefinitions(this.type, this.modifiers, this.definitions) {
+
+  VariableDefinitions(this.type,
+                      this.modifiers,
+                      this.definitions)
+      : this.metadata = null {
+    assert(modifiers != null);
+  }
+
+  // TODO(johnniwinther): Make this its own node type.
+  VariableDefinitions.forParameter(this.metadata,
+                                   this.type,
+                                   this.modifiers,
+                                   this.definitions) {
     assert(modifiers != null);
   }
 
@@ -2048,6 +2062,25 @@
   Token getEndToken() => block.getEndToken();
 }
 
+class Metadata extends Node {
+  final Token token;
+  final Expression expression;
+
+  Metadata(this.token, this.expression);
+
+  Metadata asMetadata() => this;
+
+  accept(Visitor visitor) => visitor.visitMetadata(this);
+
+  visitChildren(Visitor visitor) {
+    expression.accept(visitor);
+  }
+
+  Token getBeginToken() => token;
+
+  Token getEndToken() => expression.getEndToken();
+}
+
 class Initializers {
   static bool isSuperConstructorCall(Send node) {
     return (node.receiver == null && node.selector.isSuper()) ||
diff --git a/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart b/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
index 516cc7a..03c48e5 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/prettyprint.dart
@@ -410,6 +410,14 @@
     visitNodeWithChildren(node, "While");
   }
 
+  visitMetadata(Metadata node) {
+    openNode(node, "Metadata", {
+      "token": node.token
+    });
+    visitChildNode(node.expression, "expression");
+    closeNode();
+  }
+
   visitNode(Node node) {
     unimplemented('visitNode', node: node);
   }
diff --git a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
index 960c8b6..ebe8648 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
@@ -359,6 +359,10 @@
   }
 
   visitVariableDefinitions(VariableDefinitions node) {
+    if (node.metadata != null) {
+      visit(node.metadata);
+      sb.write(' ');
+    }
     visit(node.modifiers);
     if (!node.modifiers.nodes.isEmpty) {
       sb.write(' ');
@@ -573,6 +577,11 @@
     visit(node.identifiers);
   }
 
+  visitMetadata(Metadata node) {
+    addToken(node.token);
+    visit(node.expression);
+  }
+
   visitNode(Node node) {
     throw 'internal error'; // Should not be called.
   }
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index 5e3e8e3..5d310ce 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -466,6 +466,10 @@
     throw new UnsupportedError("");
   }
 
+  bool get isMap {
+    throw new UnsupportedError("");
+  }
+
   bool get isForwarding {
     throw new UnsupportedError("");
   }
diff --git a/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart
index b013f68..2b426cf 100644
--- a/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/container_type_mask.dart
@@ -49,6 +49,7 @@
   }
 
   bool get isContainer => true;
+  bool get isMap => false;
   bool get isExact => true;
 
   bool equalsDisregardNull(other) {
diff --git a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
index 1938dfc..39b99c2 100644
--- a/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/flat_type_mask.dart
@@ -48,6 +48,7 @@
 
   bool get isUnion => false;
   bool get isContainer => false;
+  bool get isMap => false;
   bool get isForwarding => false;
 
   // TODO(kasperl): Get rid of these. They should not be a visible
@@ -603,7 +604,12 @@
   static bool isSubtypeOf(ClassElement x, ClassElement y, Compiler compiler) {
     assert(x.isDeclaration && y.isDeclaration);
     Set<ClassElement> subtypes = compiler.world.subtypesOf(y);
-    return (subtypes != null) ? subtypes.contains(x) : false;
+    if (subtypes != null && subtypes.contains(x)) return true;
+    if (y != compiler.functionClass) return false;
+    // TODO(johnniwinther): Clean this up (function inheritance).
+    Member member =
+        x.lookupInterfaceMember(const PublicName(Compiler.CALL_OPERATOR_NAME));
+    return member != null && member.isMethod;
   }
 
   static Set<ClassElement> commonContainedClasses(FlatTypeMask x,
diff --git a/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
index ec6acab..724c27c 100644
--- a/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/forwarding_type_mask.dart
@@ -5,7 +5,7 @@
 part of types;
 
 /**
- * A type mask that wraps an other one, and delecate all its
+ * A type mask that wraps an other one, and delegate all its
  * implementation methods to it.
  */
 abstract class ForwardingTypeMask implements TypeMask {
diff --git a/sdk/lib/_internal/compiler/implementation/types/map_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/map_type_mask.dart
new file mode 100644
index 0000000..266eede
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/map_type_mask.dart
@@ -0,0 +1,111 @@
+// 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 types;
+
+/// A [MapTypeMask] is a [TypeMask] for a specific allocation
+/// site of a map (currently only internal Map class) that will get specialized
+/// once the [TypeGraphInferrer] phase finds a key and/or value type for it.
+class MapTypeMask extends ForwardingTypeMask {
+  final TypeMask forwardTo;
+
+  // The [Node] where this type mask was created.
+  final Node allocationNode;
+
+  // The [Element] where this type mask was created.
+  final Element allocationElement;
+
+  // The value type of this map.
+  final TypeMask valueType;
+
+  // The key type of this map.
+  final TypeMask keyType;
+
+  MapTypeMask(this.forwardTo,
+              this.allocationNode,
+              this.allocationElement,
+              this.keyType,
+              this.valueType);
+
+  TypeMask nullable() {
+    return isNullable
+        ? this
+        : new MapTypeMask(forwardTo.nullable(),
+                          allocationNode,
+                          allocationElement,
+                          keyType,
+                          valueType);
+  }
+
+  TypeMask nonNullable() {
+    return isNullable
+        ? new MapTypeMask(forwardTo.nonNullable(),
+                          allocationNode,
+                          allocationElement,
+                          keyType,
+                          valueType)
+        : this;
+  }
+
+  bool get isContainer => false;
+  bool get isMap => true;
+  bool get isExact => true;
+
+  bool equalsDisregardNull(other) {
+    if (other is! MapTypeMask) return false;
+    return allocationNode == other.allocationNode
+        && keyType == other.keyType
+        && valueType == other.valueType;
+  }
+
+  TypeMask intersection(TypeMask other, Compiler compiler) {
+    TypeMask forwardIntersection = forwardTo.intersection(other, compiler);
+    if (forwardIntersection.isEmpty) return forwardIntersection;
+    return forwardIntersection.isNullable
+        ? nullable()
+        : nonNullable();
+  }
+
+  TypeMask union(other, Compiler compiler) {
+    if (this == other) {
+      return this;
+    } else if (equalsDisregardNull(other)) {
+      return other.isNullable ? other : this;
+    } else if (other.isEmpty) {
+      return other.isNullable ? this.nullable() : this;
+    } else if (other.isMap
+               && keyType != null
+               && other.keyType != null
+               && valueType != null
+               && other.valueType != null) {
+      TypeMask newKeyType =
+          keyType.union(other.keyType, compiler);
+      TypeMask newValueType =
+          valueType.union(other.valueType, compiler);
+      TypeMask newForwardTo = forwardTo.union(other.forwardTo, compiler);
+      return new MapTypeMask(
+          newForwardTo, null, null, newKeyType, newValueType);
+    } else {
+      return forwardTo.union(other, compiler);
+    }
+  }
+
+  bool operator==(other) {
+    if (other is! MapTypeMask) return false;
+    return allocationNode == other.allocationNode
+        && isNullable == other.isNullable
+        && keyType == other.keyType
+        && valueType == other.valueType
+        && forwardTo == other.forwardTo;
+  }
+
+  int get hashCode {
+    return computeHashCode(
+        allocationNode, isNullable, keyType, valueType, forwardTo);
+  }
+
+  String toString() {
+    return 'Map mask: [$keyType/$valueType] type: $forwardTo';
+  }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index 24b60b4..22dca73 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -52,6 +52,7 @@
 
   bool get isUnion;
   bool get isContainer;
+  bool get isMap;
   bool get isForwarding;
 
   bool containsOnlyInt(Compiler compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index a5c9a9a..5b9999e 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -5,7 +5,6 @@
 library types;
 
 import '../dart2jslib.dart' hide Selector, TypedSelector;
-import '../dart_types.dart';
 import '../elements/elements.dart';
 import '../inferrer/type_graph_inferrer.dart' show TypeGraphInferrer;
 import '../tree/tree.dart';
@@ -14,6 +13,7 @@
 import 'concrete_types_inferrer.dart' show ConcreteTypesInferrer;
 
 part 'container_type_mask.dart';
+part 'map_type_mask.dart';
 part 'flat_type_mask.dart';
 part 'forwarding_type_mask.dart';
 part 'type_mask.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
index b632e9b..b17938d 100644
--- a/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
@@ -195,6 +195,7 @@
   bool get isExact => false;
   bool get isUnion => true;
   bool get isContainer => false;
+  bool get isMap => false;
   bool get isForwarding => false;
 
   bool isInMask(TypeMask other, Compiler compiler) {
diff --git a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
index 33897e0..7dfac97 100644
--- a/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
+++ b/sdk/lib/_internal/compiler/implementation/use_unused_api.dart
@@ -88,6 +88,7 @@
     ..asLiteralMapEntry()
     ..asLiteralNull()
     ..asLiteralSymbol()
+    ..asMetadata()
     ..asModifiers()
     ..asPart()
     ..asPartOf()
diff --git a/sdk/lib/_internal/compiler/samples/darttags/darttags.dart b/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
index 752c0e0..3a00fc6 100644
--- a/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
+++ b/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
@@ -25,14 +25,16 @@
 
 import 'dart:io';
 
-// TODO(ahe): Should be dart:mirrors.
-import '../../implementation/mirrors/mirrors.dart';
+import 'dart:mirrors';
 
 import '../../../libraries.dart'
     show LIBRARIES, LibraryInfo;
 
-import '../../implementation/mirrors/dart2js_mirror.dart'
-    show analyze, BackDoor;
+import '../../implementation/mirrors/analyze.dart'
+    show analyze;
+import '../../implementation/mirrors/dart2js_mirrors.dart'
+    show BackDoor;
+import '../../implementation/mirrors/mirrors_util.dart' show nameOf;
 
 import '../../implementation/filenames.dart';
 import '../../implementation/source_file.dart';
@@ -40,7 +42,7 @@
 import '../../implementation/util/uri_extras.dart';
 
 const DART2JS = '../../implementation/dart2js.dart';
-const DART2JS_MIRROR = '../../implementation/mirrors/dart2js_mirror.dart';
+const DART2JS_MIRROR = '../../implementation/mirrors/dart2js_mirrors.dart';
 const SDK_ROOT = '../../../../../';
 
 bool isPublicDart2jsLibrary(String name) {
@@ -106,9 +108,9 @@
   var buffer = new StringBuffer();
   SourceFile file = handler.provider.sourceFiles['$uri'];
 
-  compilationUnit.members.forEach((DeclarationMirror mirror) {
-    var tagname = mirror.simpleName;
-    var byte_offset = mirror.getBeginToken().charOffset;
+  compilationUnit.declarations.forEach((_, DeclarationMirror mirror) {
+    var tagname = nameOf(mirror);
+    var byte_offset = mirror.location.offset;
     var line_number = file.getLine(byte_offset) + 1;
 
     var lineStart = file.lineStarts[line_number - 1];
diff --git a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
index e639c4e..9306368 100644
--- a/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
+++ b/sdk/lib/_internal/compiler/samples/jsonify/jsonify.dart
@@ -5,14 +5,15 @@
 import 'dart:io';
 import 'dart:convert';
 
-// TODO(ahe): Should be dart:mirrors.
-import '../../implementation/mirrors/mirrors.dart';
+import 'dart:mirrors';
 
 import '../../../libraries.dart'
     show LIBRARIES, LibraryInfo;
 
-import '../../implementation/mirrors/dart2js_mirror.dart'
-    show analyze, BackDoor;
+import '../../implementation/mirrors/analyze.dart'
+    show analyze;
+import '../../implementation/mirrors/dart2js_mirrors.dart'
+    show BackDoor;
 
 import '../../implementation/filenames.dart';
 import '../../implementation/source_file.dart';
diff --git a/sdk/lib/_internal/dartdoc/.gitignore b/sdk/lib/_internal/dartdoc/.gitignore
deleted file mode 100644
index e68c6ca..0000000
--- a/sdk/lib/_internal/dartdoc/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-# Generated output.
-/docs/
-
-# Compiled .js output.
-static/client-static.js
-static/client-live-nav.js
\ No newline at end of file
diff --git a/sdk/lib/_internal/dartdoc/README.txt b/sdk/lib/_internal/dartdoc/README.txt
deleted file mode 100644
index ad4ddad..0000000
--- a/sdk/lib/_internal/dartdoc/README.txt
+++ /dev/null
@@ -1,84 +0,0 @@
-Dartdoc generates static HTML documentation from Dart code.
-
-To use it, from this directory, run:
-
-    $ dartdoc <path to .dart file>
-
-This will create a "docs" directory with the docs for your libraries.
-
-
-How docs are generated
-----------------------
-
-To make beautiful docs from your library, dartdoc parses it and every library it
-imports (recursively). From each library, it parses all classes and members,
-finds the associated doc comments and builds crosslinked docs from them.
-
-"Doc comments" can be in one of a few forms:
-
-    /**
-     * JavaDoc style block comments.
-     */
-
-    /** Which can also be single line. */
-
-    /// Triple-slash line comments.
-    /// Which can be multiple lines.
-
-The body of a doc comment will be parsed as markdown which means you can apply
-most of the formatting and structuring you want while still having docs that
-look nice in plain text. For example:
-
-    /// This is a doc comment. This is the first paragraph in the comment. It
-    /// can span multiple lines.
-    ///
-    /// A blank line starts a new paragraph like this one.
-    ///
-    /// *   Unordered lists start with `*` or `-` or `+`.
-    /// *   And can have multiple items.
-    ///     1. You can nest lists.
-    ///     2. Like this numbered one.
-    ///
-    /// ---
-    ///
-    /// Three dashes, underscores, or tildes on a line by themselves create a
-    /// horizontal rule.
-    ///
-    ///     to.get(a.block + of.code) {
-    ///       indent(it, 4.spaces);
-    ///       like(this);
-    ///     }
-    ///
-    /// There are a few inline styles you can apply: *emphasis*, **strong**,
-    /// and `inline code`. You can also use underscores for _emphasis_ and
-    /// __strong__.
-    ///
-    /// An H1 header using equals on the next line
-    /// ==========================================
-    ///
-    /// And an H2 in that style using hyphens
-    /// -------------------------------------
-    ///
-    /// # Or an H1 - H6 using leading hashes
-    /// ## H2
-    /// ### H3
-    /// #### H4 you can also have hashes at then end: ###
-    /// ##### H5
-    /// ###### H6
-
-There is also an extension to markdown specific to dartdoc: A name inside
-square brackets that is not a markdown link (i.e. doesn't have square brackets
-or parentheses following it) like:
-
-    Calls [someMethod], passing in [arg].
-
-is understood to be the name of some member or type that's in the scope of the
-member where that comment appears. Dartdoc will automatically figure out what
-the name refers to and generate an approriate link to that member or type.
-
-
-Attribution
------------
-
-dartdoc uses the delightful Silk icon set by Mark James.
-http://www.famfamfam.com/lab/icons/silk/
diff --git a/sdk/lib/_internal/dartdoc/bin/dartdoc.dart b/sdk/lib/_internal/dartdoc/bin/dartdoc.dart
deleted file mode 100644
index 4ae00ab..0000000
--- a/sdk/lib/_internal/dartdoc/bin/dartdoc.dart
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/**
- * To generate docs for a library, run this script with the path to an
- * entrypoint .dart file, like:
- *
- *     $ dart dartdoc.dart foo.dart
- *
- * This will create a "docs" directory with the docs for your libraries. To
- * create these beautiful docs, dartdoc parses your library and every library
- * it imports (recursively). From each library, it parses all classes and
- * members, finds the associated doc comments and builds crosslinked docs from
- * them.
- */
-library dartdoc;
-
-import 'dart:async';
-import 'dart:io';
-
-import '../lib/dartdoc.dart';
-import '../lib/src/dartdoc/utils.dart';
-import 'package:args/args.dart';
-import 'package:path/path.dart' as path;
-
-/**
- * Run this from the `lib/_internal/dartdoc` directory.
- */
-main(List<String> arguments) {
-  // Need this because ArgParser.getUsage doesn't show command invocation.
-  final USAGE = 'Usage dartdoc [options] <entrypoint(s)>\n[options] include:';
-
-  final dartdoc = new Dartdoc();
-
-  final argParser = new ArgParser();
-
-  String libPath = path.join(scriptDir, '..', '..', '..', '..');
-
-  String packageRoot;
-
-  argParser.addFlag('no-code',
-      help: 'Do not include source code in the documentation.',
-      defaultsTo: false, negatable: false,
-      callback: (noCode) => dartdoc.includeSource = !noCode);
-
-  argParser.addOption('mode', abbr: 'm',
-      help: 'Define how HTML pages are generated.',
-      allowed: ['static', 'live-nav'], allowedHelp: {
-        'static': 'Generates completely static HTML containing\n'
-          'everything you need to browse the docs. The only\n'
-          'client side behavior is trivial stuff like syntax\n'
-          'highlighting code, and the find-as-you-type search\n'
-          'box.',
-        'live-nav': '(Default) Generated docs do not included baked HTML\n'
-          'navigation. Instead a single `nav.json` file is\n'
-          'created and the appropriate navigation is generated\n'
-          'client-side by parsing that and building HTML.\n'
-          '\tThis dramatically reduces the generated size of\n'
-          'the HTML since a large fraction of each static page\n'
-          'is just redundant navigation links.\n'
-          '\tIn this mode, the browser will do a XHR for\n'
-          'nav.json which means that to preview docs locallly,\n'
-          'you will need to enable requesting file:// links in\n'
-          'your browser or run a little local server like\n'
-          '`python -m  SimpleHTTPServer`.'},
-        defaultsTo: 'live-nav',
-        callback: (genMode) {
-          dartdoc.mode = (genMode == 'static' ? MODE_STATIC : MODE_LIVE_NAV);
-        });
-
-  argParser.addFlag('generate-app-cache',
-      help: 'Generates the App Cache manifest file, enabling\n'
-        'offline doc viewing.',
-        defaultsTo: false, negatable: false,
-        callback: (generate) => dartdoc.generateAppCache = generate);
-
-  argParser.addFlag('omit-generation-time',
-      help: 'Omits generation timestamp from output.',
-      defaultsTo: false, negatable: false,
-      callback: (genTimestamp) => dartdoc.omitGenerationTime = genTimestamp);
-
-  argParser.addFlag('verbose', abbr: 'v',
-      help: 'Print verbose information during generation.',
-      defaultsTo: false, negatable: false,
-      callback: (verb) => dartdoc.verbose = verb);
-
-  argParser.addFlag('include-api',
-      help: 'Include the used API libraries in the generated\n'
-        'documentation. If the --link-api option is used,\n'
-        'this option is ignored.',
-      defaultsTo: false, negatable: false,
-      callback: (incApi) => dartdoc.includeApi = incApi);
-
-  argParser.addFlag('link-api',
-      help: 'Link to the online language API in the generated\n'
-        'documentation. The option overrides inclusion\n'
-        'through --include-api or --include-lib.',
-      defaultsTo: false, negatable: false,
-      callback: (linkApi) => dartdoc.linkToApi = linkApi);
-
-  argParser.addFlag('show-private',
-      help: 'Document private types and members.',
-      defaultsTo: false,
-      callback: (showPrivate) => dartdoc.showPrivate = showPrivate);
-
-  argParser.addFlag('inherit-from-object',
-      help: 'Show members inherited from Object.',
-      defaultsTo: false, negatable: false,
-      callback: (inherit) => dartdoc.inheritFromObject = inherit);
-
-  argParser.addFlag('enable-diagnostic-colors', negatable: false);
-
-  argParser.addOption('out',
-      help: 'Generates files into directory specified. If\n'
-        'omitted the files are generated into ./docs/',
-      callback: (outDir) {
-        if(outDir != null) {
-          dartdoc.outputDir = outDir;
-        }
-      });
-
-  argParser.addOption('include-lib',
-      help: 'Use this option to explicitly specify which\n'
-        'libraries to include in the documentation. If\n'
-        'omitted, all used libraries are included by\n'
-        'default. Specify a comma-separated list of\n'
-        'library names, or call this option multiple times.',
-      callback: (incLibs) {
-        if(!incLibs.isEmpty) {
-          List<String> allLibs = new List<String>();
-          for(final lst in incLibs) {
-            var someLibs = lst.split(',');
-            for(final lib in someLibs) {
-              allLibs.add(lib);
-            }
-          }
-          dartdoc.includedLibraries = allLibs;
-        }
-      }, allowMultiple: true);
-
-  argParser.addOption('exclude-lib',
-      help: 'Use this option to explicitly specify which\n'
-        'libraries to exclude from the documentation. If\n'
-        'omitted, no libraries are excluded. Specify a\n'
-        'comma-separated list of library names, or call\n'
-        'this option multiple times.',
-      callback: (excLibs) {
-        if(!excLibs.isEmpty) {
-          List<String> allLibs = new List<String>();
-          for(final lst in excLibs) {
-            var someLibs = lst.split(',');
-            for(final lib in someLibs) {
-              allLibs.add(lib);
-            }
-          }
-          dartdoc.excludedLibraries = allLibs;
-        }
-      }, allowMultiple: true);
-
-  argParser.addOption('package-root',
-      help: 'Sets the package directory to the specified directory.\n'
-        'If omitted the package directory is the closest packages directory to'
-        ' the entrypoint.',
-      callback: (packageDir) {
-        if(packageDir != null) {
-          packageRoot = packageDir;
-        }
-      });
-
-  argParser.addOption('library-root',
-      help: 'Sets the library root directory to the specified directory.',
-      callback: (libraryRoot) {
-        if (libraryRoot != null) {
-          libPath = libraryRoot;
-        }
-      });
-
-  // TODO(amouravski): This method is deprecated. Remove on April 22.
-  argParser.addOption('pkg',
-      help: 'Deprecated: same as --package-root.',
-      callback: (packageDir) {
-        if(packageDir != null) {
-          packageRoot = packageDir;
-        }
-      });
-
-  dartdoc.dartdocPath = path.join(libPath, 'lib', '_internal', 'dartdoc');
-
-  if (arguments.isEmpty) {
-    print('No arguments provided.');
-    print(USAGE);
-    print(argParser.getUsage());
-    exit(1);
-  }
-
-  final entrypoints = <Uri>[];
-  try {
-    final option = argParser.parse(arguments, allowTrailingOptions: true);
-
-    // This checks to see if the root of all entrypoints is the same.
-    // If it is not, then we display a warning, as package imports might fail.
-    var entrypointRoot;
-    for (final entrypoint in option.rest) {
-      var uri = Uri.parse(entrypoint);
-
-      // If it looks like it was a file path (no scheme, or a one letter scheme
-      // which is likely a drive letter on Windows), turn it into a file URL.
-      if (uri.scheme == '' || uri.scheme.length == 1) {
-        uri = path.toUri(entrypoint);
-      }
-
-      entrypoints.add(uri);
-
-      if (uri.scheme != 'file') continue;
-      if (entrypointRoot == null) {
-        entrypointRoot = path.dirname(entrypoint);
-      } else if (entrypointRoot != path.dirname(entrypoint)) {
-        print('Warning: entrypoints are at different directories. "package:"'
-            ' imports may fail.');
-      }
-    }
-  } on FormatException catch (e) {
-    print(e.message);
-    print(USAGE);
-    print(argParser.getUsage());
-    exit(1);
-  }
-
-  if (entrypoints.isEmpty) {
-    print('No entrypoints provided.');
-    print(argParser.getUsage());
-    exit(1);
-  }
-
-  if (packageRoot == null) packageRoot = _getPackageRoot(entrypoints);
-
-  cleanOutputDirectory(dartdoc.outputDir);
-
-  // Start the analysis and documentation.
-  dartdoc.documentLibraries(entrypoints, libPath, packageRoot)
-    // Prepare the dart2js script code and copy static resources.
-    // TODO(amouravski): move compileScript out and pre-generate the client
-    // scripts. This takes a long time and the js hardly ever changes.
-    .then((_) => compileScript(dartdoc.mode, dartdoc.outputDir, libPath,
-          dartdoc.tmpPath))
-    .then((_) => copyDirectory(
-          path.join(libPath, 'lib', '_internal', 'dartdoc', 'static'),
-          dartdoc.outputDir))
-    .then((_) {
-      print(dartdoc.status);
-      if (dartdoc.totals == 0) {
-        exit(1);
-      }
-    })
-    .catchError((e, trace) {
-      print('Error: generation failed: ${e}');
-      if (trace != null) print("StackTrace: $trace");
-      dartdoc.cleanup();
-      exit(1);
-    })
-    .whenComplete(() => dartdoc.cleanup());
-}
-
-String _getPackageRoot(List<Uri> entrypoints) {
-  // Check if there's a `packages` directory in the entry point directory.
-  var fileEntrypoint = entrypoints.firstWhere(
-      (entrypoint) => entrypoint.scheme == 'file',
-      orElse: () => null);
-  if (fileEntrypoint == null) return;
-
-  var script = path.normalize(path.absolute(path.fromUri(fileEntrypoint)));
-  var dir = path.join(path.dirname(script), 'packages/');
-  if (new Directory(dir).existsSync()) return dir;
-
-  // If there is not, then check if the entrypoint is somewhere in a `lib`
-  // directory.
-  var parts = path.split(path.dirname(script));
-  var libDir = parts.lastIndexOf('lib');
-  if (libDir > 0) {
-    return path.join(path.joinAll(parts.take(libDir)), 'packages');
-  } else {
-    return null;
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/dartdoc.status b/sdk/lib/_internal/dartdoc/dartdoc.status
deleted file mode 100644
index 336e19b..0000000
--- a/sdk/lib/_internal/dartdoc/dartdoc.status
+++ /dev/null
@@ -1,15 +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.
-
-test/markdown_test: Pass
-test/dartdoc_test: Pass, Slow  # Issue 16311
-test/dartdoc_search_test: Pass, Skip
-
-# Dartdoc only runs on the VM, so just rule out all compilers.
-[ $compiler == dart2js || $compiler == dart2dart ]
-*: Skip
-
-# Dartdoc only runs on the standalone VM, not in dartium.
-[ $runtime == drt || $runtime == dartium ]
-*: Skip
diff --git a/sdk/lib/_internal/dartdoc/lib/classify.dart b/sdk/lib/_internal/dartdoc/lib/classify.dart
deleted file mode 100644
index e4ed4db..0000000
--- a/sdk/lib/_internal/dartdoc/lib/classify.dart
+++ /dev/null
@@ -1,206 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library classify;
-
-import '../../compiler/implementation/scanner/scannerlib.dart';
-// TODO(rnystrom): Use "package:" URL (#4968).
-import 'markdown.dart' as md;
-
-/**
- * Kinds of tokens that we care to highlight differently. The values of the
- * fields here will be used as CSS class names for the generated spans.
- */
-class Classification {
-  static const NONE = null;
-  static const ERROR = "e";
-  static const COMMENT = "c";
-  static const IDENTIFIER = "i";
-  static const KEYWORD = "k";
-  static const OPERATOR = "o";
-  static const STRING = "s";
-  static const NUMBER = "n";
-  static const PUNCTUATION = "p";
-
-  // A few things that are nice to make different:
-  static const TYPE_IDENTIFIER = "t";
-
-  // Between a keyword and an identifier
-  static const SPECIAL_IDENTIFIER = "r";
-
-  static const ARROW_OPERATOR = "a";
-
-  static const STRING_INTERPOLATION = 'si';
-}
-
-/// Returns a marked up HTML string. If the code does not appear to be valid
-/// Dart code, returns the original [text].
-String classifySource(String text) {
-  try {
-    var html = new StringBuffer();
-    var tokenizer = new StringScanner.fromString(text, includeComments: true);
-
-    var whitespaceOffset = 0;
-    var token = tokenizer.tokenize();
-    var inString = false;
-    while (token.kind != EOF_TOKEN) {
-      html.write(text.substring(whitespaceOffset, token.charOffset));
-      whitespaceOffset = token.charOffset + token.slowCharCount;
-
-      // Track whether or not we're in a string.
-      switch (token.kind) {
-        case STRING_TOKEN:
-        case STRING_INTERPOLATION_TOKEN:
-          inString = true;
-          break;
-      }
-
-      final kind = classify(token);
-      final escapedText = md.escapeHtml(token.value);
-      if (kind != null) {
-        // Add a secondary class to tokens appearing within a string so that
-        // we can highlight tokens in an interpolation specially.
-        var stringClass = inString ? Classification.STRING_INTERPOLATION : '';
-        html.write('<span class="$kind $stringClass">$escapedText</span>');
-      } else {
-        html.write(escapedText);
-      }
-
-      // Track whether or not we're in a string.
-      if (token.kind == STRING_TOKEN) {
-        inString = false;
-      }
-      token = token.next;
-    }
-    return html.toString();
-  } catch (e) {
-    return text;
-  }
-}
-
-bool _looksLikeType(String name) {
-  // If the name looks like an UppercaseName, assume it's a type.
-  return _looksLikePublicType(name) || _looksLikePrivateType(name);
-}
-
-bool _looksLikePublicType(String name) {
-  // If the name looks like an UppercaseName, assume it's a type.
-  return name.length >= 2 && isUpper(name[0]) && isLower(name[1]);
-}
-
-bool _looksLikePrivateType(String name) {
-  // If the name looks like an _UppercaseName, assume it's a type.
-  return (name.length >= 3 && name[0] == '_' && isUpper(name[1])
-    && isLower(name[2]));
-}
-
-// These ensure that they don't return "true" if the string only has symbols.
-bool isUpper(String s) => s.toLowerCase() != s;
-bool isLower(String s) => s.toUpperCase() != s;
-
-String classify(Token token) {
-  switch (token.kind) {
-    case IDENTIFIER_TOKEN:
-      // Special case for names that look like types.
-      final text = token.value;
-      if (_looksLikeType(text)
-          || text == 'num'
-          || text == 'bool'
-          || text == 'int'
-          || text == 'double') {
-        return Classification.TYPE_IDENTIFIER;
-      }
-      return Classification.IDENTIFIER;
-
-    case STRING_TOKEN:
-    case STRING_INTERPOLATION_TOKEN:
-      return Classification.STRING;
-
-    case INT_TOKEN:
-    case HEXADECIMAL_TOKEN:
-    case DOUBLE_TOKEN:
-      return Classification.NUMBER;
-
-    case COMMENT_TOKEN:
-      return Classification.COMMENT;
-
-    // => is so awesome it is in a class of its own.
-    case FUNCTION_TOKEN:
-      return Classification.ARROW_OPERATOR;
-
-    case OPEN_PAREN_TOKEN:
-    case CLOSE_PAREN_TOKEN:
-    case OPEN_SQUARE_BRACKET_TOKEN:
-    case CLOSE_SQUARE_BRACKET_TOKEN:
-    case OPEN_CURLY_BRACKET_TOKEN:
-    case CLOSE_CURLY_BRACKET_TOKEN:
-    case COLON_TOKEN:
-    case SEMICOLON_TOKEN:
-    case COMMA_TOKEN:
-    case PERIOD_TOKEN:
-    case PERIOD_PERIOD_TOKEN:
-      return Classification.PUNCTUATION;
-
-    case PLUS_PLUS_TOKEN:
-    case MINUS_MINUS_TOKEN:
-    case TILDE_TOKEN:
-    case BANG_TOKEN:
-    case EQ_TOKEN:
-    case BAR_EQ_TOKEN:
-    case CARET_EQ_TOKEN:
-    case AMPERSAND_EQ_TOKEN:
-    case LT_LT_EQ_TOKEN:
-    case GT_GT_EQ_TOKEN:
-    case PLUS_EQ_TOKEN:
-    case MINUS_EQ_TOKEN:
-    case STAR_EQ_TOKEN:
-    case SLASH_EQ_TOKEN:
-    case TILDE_SLASH_EQ_TOKEN:
-    case PERCENT_EQ_TOKEN:
-    case QUESTION_TOKEN:
-    case BAR_BAR_TOKEN:
-    case AMPERSAND_AMPERSAND_TOKEN:
-    case BAR_TOKEN:
-    case CARET_TOKEN:
-    case AMPERSAND_TOKEN:
-    case LT_LT_TOKEN:
-    case GT_GT_TOKEN:
-    case PLUS_TOKEN:
-    case MINUS_TOKEN:
-    case STAR_TOKEN:
-    case SLASH_TOKEN:
-    case TILDE_SLASH_TOKEN:
-    case PERCENT_TOKEN:
-    case EQ_EQ_TOKEN:
-    case BANG_EQ_TOKEN:
-    case EQ_EQ_EQ_TOKEN:
-    case BANG_EQ_EQ_TOKEN:
-    case LT_TOKEN:
-    case GT_TOKEN:
-    case LT_EQ_TOKEN:
-    case GT_EQ_TOKEN:
-    case INDEX_TOKEN:
-    case INDEX_EQ_TOKEN:
-      return Classification.OPERATOR;
-
-    // Color keyword token. Most are colored as keywords.
-    case HASH_TOKEN:
-    case KEYWORD_TOKEN:
-      if (token.stringValue == 'void') {
-        // Color "void" as a type.
-        return Classification.TYPE_IDENTIFIER;
-      }
-      if (token.stringValue == 'this' || token.stringValue == 'super') {
-        // Color "this" and "super" as identifiers.
-        return Classification.SPECIAL_IDENTIFIER;
-      }
-      return Classification.KEYWORD;
-
-    case EOF_TOKEN:
-      return Classification.NONE;
-
-    default:
-      return Classification.NONE;
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
deleted file mode 100644
index 5ba7f0e..0000000
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ /dev/null
@@ -1,2333 +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.
-
-/**
- * To generate docs for a library, run this script with the path to an
- * entrypoint .dart file, like:
- *
- *     $ dart dartdoc.dart foo.dart
- *
- * This will create a "docs" directory with the docs for your libraries. To
- * create these beautiful docs, dartdoc parses your library and every library
- * it imports (recursively). From each library, it parses all classes and
- * members, finds the associated doc comments and builds crosslinked docs from
- * them.
- */
-library dartdoc;
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:io';
-import 'dart:isolate';
-import 'dart:math';
-
-import 'package:path/path.dart' as path;
-
-import 'classify.dart';
-import 'markdown.dart' as md;
-import 'universe_serializer.dart';
-
-import 'src/dartdoc/nav.dart';
-import 'src/dartdoc/utils.dart';
-import 'src/export_map.dart';
-import 'src/json_serializer.dart' as json_serializer;
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import 'src/dart2js_mirrors.dart' as dart2js;
-import '../../compiler/implementation/mirrors/mirrors.dart';
-import '../../compiler/implementation/mirrors/mirrors_util.dart';
-import '../../libraries.dart';
-
-/**
- * Generates completely static HTML containing everything you need to browse
- * the docs. The only client side behavior is trivial stuff like syntax
- * highlighting code.
- */
-const MODE_STATIC = 0;
-
-/**
- * Generated docs do not include baked HTML navigation. Instead, a single
- * `nav.json` file is created and the appropriate navigation is generated
- * client-side by parsing that and building HTML.
- *
- * This dramatically reduces the generated size of the HTML since a large
- * fraction of each static page is just redundant navigation links.
- *
- * In this mode, the browser will do a XHR for nav.json which means that to
- * preview docs locally, you will need to enable requesting file:// links in
- * your browser or run a little local server like `python -m SimpleHTTPServer`.
- */
-const MODE_LIVE_NAV = 1;
-
-const API_LOCATION = 'http://api.dartlang.org/';
-
-/**
- * Gets the full path to the directory containing the entrypoint of the current
- * script. In other words, if you invoked dartdoc, directly, it will be the
- * path to the directory containing `dartdoc.dart`. If you're running a script
- * that imports dartdoc, it will be the path to that script.
- */
-// TODO(johnniwinther): Convert to final (lazily initialized) variables when
-// the feature is supported.
-String get scriptDir => path.dirname(Platform.script.toFilePath());
-
-/**
- * Deletes and recreates the output directory at [path] if it exists.
- */
-void cleanOutputDirectory(String path) {
-  final outputDir = new Directory(path);
-  if (outputDir.existsSync()) {
-    outputDir.deleteSync(recursive: true);
-  }
-  outputDir.createSync();
-}
-
-/**
- * Copies all of the files in the directory [from] to [to]. Does *not*
- * recursively copy subdirectories.
- *
- * Note: runs asynchronously, so you won't see any files copied until after the
- * event loop has had a chance to pump (i.e. after `main()` has returned).
- */
-Future copyDirectory(String from, String to) {
-  print('Copying static files...');
-  final completer = new Completer();
-  final fromDir = new Directory(from);
-  var futureList = [];
-  fromDir.list(recursive: false).listen(
-      (FileSystemEntity entity) {
-        if (entity is File) {
-          final name = path.basename(entity.path);
-          // TODO(rnystrom): Hackish. Ignore 'hidden' files like .DS_Store.
-          if (name.startsWith('.')) return;
-
-          File fromFile = entity;
-          File toFile = new File(path.join(to, name));
-          futureList.add(fromFile.openRead().pipe(toFile.openWrite()));
-        }
-      },
-      onDone: () => Future.wait(futureList).then((_) => completer.complete()),
-      onError: completer.completeError);
-  return completer.future;
-}
-
-/**
- * Compiles the dartdoc client-side code to JavaScript using Dart2js.
- */
-Future compileScript(int mode, String outputDir, String libPath, String tmpPath) {
-  print('Compiling client JavaScript...');
-  var clientScript = (mode == MODE_STATIC) ?  'static' : 'live-nav';
-  var dartdocLibPath = path.join(libPath, 'lib', '_internal', 'dartdoc', 'lib');
-  var dartPath = mode == MODE_STATIC ?
-    path.join(tmpPath, 'client.dart') :
-    path.join(dartdocLibPath, 'src', 'client', 'client-live-nav.dart');
-
-  var jsPath = path.join(outputDir, 'client-$clientScript.js');
-
-  // dart2js takes a String, but it expects that to be a Uri, not a file
-  // system path.
-  libPath = path.toUri(libPath).toString();
-  dartPath = path.toUri(dartPath).toString();
-
-  return dart2js.compile(
-      dartPath, libPath,
-      options: const <String>['--categories=Client,Server', '--minify'])
-  .then((jsCode) {
-    if (jsCode == null) throw new StateError("No javascript was generated.");
-    writeString(new File(jsPath), jsCode);
-  });
-}
-
-/**
- * Package manifest containing all information required to render the main page
- * for a package.
- *
- * The manifest specifies where to load the [LibraryElement]s describing each
- * library rather than including them directly.
- * For our purposes we treat the core Dart libraries as a package.
- */
-class PackageManifest {
-  /** Package name. */
-  final name;
-  /** Package description */
-  final description;
-  /** Libraries contained in this package. */
-  final List<Reference> libraries = <Reference>[];
-  /**
-   * Descriptive string describing the version# of the package.
-   *
-   * The current format for dart-sdk versions is
-   * $MAJOR.$MINOR.$BUILD.$PATCH$revisionString$userNameString
-   * For example: 0.1.2.0_r18233_johndoe
-   */
-  final String fullVersion;
-  /**
-   * Source control revision number for the package. For SVN this is a number
-   * while for GIT it is a hash.
-   */
-  final String revision;
-  /**
-   * Path to the directory containing data files for each library.
-   *
-   * Currently this is the serialized json version of the LibraryElement for
-   * the library.
-   */
-  String location;
-  /**
-   * Packages depended on by this package.
-   * We currently store the entire manifest for the depency here the manifests
-   * are small.  We may want to change this to a reference in the future.
-   */
-  final List<PackageManifest> dependencies = <PackageManifest>[];
-
-  PackageManifest(this.name, this.description, this.fullVersion, this.revision);
-}
-
-class Dartdoc {
-
-  /** Set to `false` to not include the source code in the generated docs. */
-  bool includeSource = true;
-
-  /**
-   * Dartdoc can generate docs in a few different ways based on how dynamic you
-   * want the client-side behavior to be. The value for this should be one of
-   * the `MODE_` constants.
-   */
-  int mode = MODE_LIVE_NAV;
-
-  /**
-   * Generates the App Cache manifest file, enabling offline doc viewing.
-   */
-  bool generateAppCache = false;
-
-  /** Path to the dartdoc directory. */
-  String dartdocPath;
-
-  /** Path to generate HTML files into. */
-  String outputDir = 'docs';
-
-  /**
-   * The title used for the overall generated output. Set this to change it.
-   */
-  String mainTitle = 'Dart Documentation';
-
-  /**
-   * The URL that the Dart logo links to. Defaults "index.html", the main
-   * page for the generated docs, but can be anything.
-   */
-  String mainUrl = 'index.html';
-
-  /**
-   * The Google Custom Search ID that should be used for the search box. If
-   * this is `null` then no search box will be shown.
-   */
-  String searchEngineId = null;
-
-  /* The URL that the embedded search results should be displayed on. */
-  String searchResultsUrl = 'results.html';
-
-  /** Set this to add footer text to each generated page. */
-  String footerText = null;
-
-  /** Set this to omit generation timestamp from output */
-  bool omitGenerationTime = false;
-
-  /** Set by Dartdoc user to print extra information during generation. */
-  bool verbose = false;
-
-  /** Set this to include API libraries in the documentation. */
-  bool includeApi = false;
-
-  /** Set this to generate links to the online API. */
-  bool linkToApi = false;
-
-  /** Set this to generate docs for private types and members. */
-  bool showPrivate = false;
-
-  /** Set this to inherit from Object. */
-  bool inheritFromObject = false;
-
-  /** Version of the sdk or package docs are being generated for. */
-  String version;
-
-  /** Set this to select the libraries to include in the documentation. */
-  List<String> includedLibraries = const <String>[];
-
-  /** Set this to select the libraries to exclude from the documentation. */
-  List<String> excludedLibraries = const <String>[];
-
-  /** The package root for `package:` imports. */
-  String _packageRoot;
-
-  /** The map containing all the exports for each library. */
-  ExportMap _exports;
-
-  /** The path to a temporary directory used by Dartdoc. */
-  String tmpPath;
-
-  /**
-   * This list contains the libraries sorted in by the library name.
-   */
-  List<LibraryMirror> _sortedLibraries;
-
-  /**
-   * A map from hidden libraries to lists of [Export]s that export those
-   * libraries from visible libraries. This is used to determine what public
-   * library any given entity belongs to.
-   *
-   * The lists of exports are sorted so that exports that hide the fewest number
-   * of members come first.
-   */
-  Map<LibraryMirror, List<Export>> _hiddenLibraryExports;
-
-  /** The library that we're currently generating docs for. */
-  LibraryMirror _currentLibrary;
-
-  /** The type that we're currently generating docs for. */
-  ClassMirror _currentType;
-
-  /** The member that we're currently generating docs for. */
-  MemberMirror _currentMember;
-
-  /** The path to the file currently being written to, relative to [outdir]. */
-  String _filePath;
-
-  /** The file currently being written to. */
-  StringBuffer _file;
-
-  int _totalLibraries = 0;
-  int _totalTypes = 0;
-  int _totalMembers = 0;
-
-  int get totalLibraries => _totalLibraries;
-  int get totalTypes => _totalTypes;
-  int get totalMembers => _totalMembers;
-
-  // Check if the compilation has started and finished.
-  bool _started = false;
-  bool _finished = false;
-
-  /**
-   * Prints the status of dartdoc.
-   *
-   * Prints whether dartdoc is running, whether dartdoc has finished
-   * succesfully or not, and how many libraries, types, and members were
-   * documented.
-   */
-  String get status {
-    // TODO(amouravski): Make this more full featured and remove all other
-    // prints and put them under verbose flag.
-    if (!_started) {
-      return 'Documentation has not yet started.';
-    } else if (!_finished) {
-      return 'Documentation in progress -- documented $_statisticsSummary so far.';
-    } else {
-      if (totals == 0) {
-        return 'Documentation complete -- warning: nothing was documented!';
-      } else {
-        return 'Documentation complete -- documented $_statisticsSummary.';
-      }
-    }
-  }
-
-  int get totals => totalLibraries + totalTypes + totalMembers;
-
-  String get _statisticsSummary =>
-      '${totalLibraries} libraries, ${totalTypes} types, and '
-      '${totalMembers} members';
-
-  static const List<String> COMPILER_OPTIONS =
-      const <String>['--preserve-comments', '--categories=Client,Server'];
-
-  /// Resolves Dart links to the correct Node.
-  md.Resolver dartdocResolver;
-
-  // Add support for [:...:]-style code to the markdown parser.
-  List<md.InlineSyntax> dartdocSyntaxes =
-    [new md.CodeSyntax(r'\[:\s?((?:.|\n)*?)\s?:\]')];
-
-  Dartdoc() {
-    tmpPath = Directory.systemTemp.createTempSync('dartdoc_').path;
-    dartdocResolver = (String name) => resolveNameReference(name,
-        currentLibrary: _currentLibrary, currentType: _currentType,
-        currentMember: _currentMember);
-  }
-
-  /**
-   * Returns `true` if [library] is included in the generated documentation.
-   */
-  bool shouldIncludeLibrary(LibraryMirror library) {
-    if (shouldLinkToPublicApi(library)) {
-      return false;
-    }
-    var includeByDefault = true;
-    String libraryName = displayName(library);
-    if (excludedLibraries.contains(libraryName)) {
-      return false;
-    }
-    if (!includedLibraries.isEmpty) {
-      includeByDefault = false;
-      if (includedLibraries.contains(libraryName)) {
-        return true;
-      }
-    }
-    Uri uri = library.uri;
-    if (uri.scheme == 'dart') {
-      String suffix = uri.path;
-      LibraryInfo info = LIBRARIES[suffix];
-      if (info != null) {
-        return info.documented && includeApi;
-      }
-    }
-    return includeByDefault;
-  }
-
-  /**
-   * Returns `true` if links to the public API should be generated for
-   * [library].
-   */
-  bool shouldLinkToPublicApi(LibraryMirror library) {
-    if (linkToApi) {
-      Uri uri = library.uri;
-      if (uri.scheme == 'dart') {
-        String suffix = uri.path;
-        LibraryInfo info = LIBRARIES[suffix];
-        if (info != null) {
-          return info.documented;
-        }
-      }
-    }
-    return false;
-  }
-
-  String get footerContent{
-    var footerItems = [];
-    if (!omitGenerationTime) {
-      footerItems.add("This page was generated at ${new DateTime.now()}");
-    }
-    if (footerText != null) {
-      footerItems.add(footerText);
-    }
-    var content = '';
-    for (int i = 0; i < footerItems.length; i++) {
-      if (i > 0) {
-        content += '\n';
-      }
-      content += '<div>${footerItems[i]}</div>';
-    }
-    return content;
-  }
-
-  Future documentLibraries(List<Uri> libraryList, String libPath,
-      String packageRoot) {
-    _packageRoot = packageRoot;
-
-    // dart2js takes a String, but it expects that to be a Uri, not a file
-    // system path.
-    libPath = path.toUri(libPath).toString();
-
-    if (packageRoot != null) {
-      packageRoot = path.toUri(packageRoot).toString();
-    }
-
-    // TODO(amouravski): make all of these print statements into logging
-    // statements.
-    print('Analyzing libraries...');
-    return dart2js.analyze(
-        libraryList.map((uri) => uri.toString()).toList(),
-        libPath, packageRoot: packageRoot, options: COMPILER_OPTIONS)
-      .then((MirrorSystem mirrors) {
-        print('Generating documentation...');
-        _document(mirrors);
-      });
-  }
-
-  void _document(MirrorSystem mirrors) {
-    _exports = new ExportMap(mirrors);
-    _started = true;
-
-
-    // Remove duplicated libraries. This is a hack because libraries can
-    // get picked up multiple times (dartbug.com/11826) which will go away
-    // with the new docgen. The reason we hit this issue is that we attempt
-    // to dart2js.analyze all packages in the repo together, which results
-    // in packages getting referenced with different URI's (../../pkg versus
-    // ../../out/ReleaseIA32/packages versus package:).
-    _sortedLibraries = new Map.fromIterable(
-        mirrors.libraries.values.where(shouldIncludeLibrary),
-        key: displayName).values.toList();
-
-    // Sort the libraries by name (not key).
-    _sortedLibraries.sort((x, y) {
-      return displayName(x).toUpperCase().compareTo(
-          displayName(y).toUpperCase());
-    });
-
-    _hiddenLibraryExports = _generateHiddenLibraryExports();
-
-    // Generate the docs.
-    if (mode == MODE_LIVE_NAV) {
-      docNavigationJson();
-    } else {
-      docNavigationDart();
-    }
-
-    docIndex();
-    for (final library in _sortedLibraries) {
-      docLibrary(library);
-    }
-
-    if (generateAppCache) {
-      generateAppCacheManifest();
-    }
-
-    // TODO(nweiz): properly handle exports when generating JSON.
-    // TODO(jacobr): handle arbitrary pub packages rather than just the system
-    // libraries.
-    var revision = '0';
-    if (version != null) {
-      var match = new RegExp(r"_r(\d+)").firstMatch(version);
-      if (match != null) {
-        revision = match.group(1);
-      } else {
-        print("Warning: could not parse version: $version");
-      }
-    }
-    var packageManifest = new PackageManifest('dart:', 'Dart System Libraries',
-        version, revision);
-
-    for (final lib in _sortedLibraries) {
-      var libraryElement = new LibraryElement(
-          lib, lookupMdnComment: lookupMdnComment)
-          ..stripDuplicateUris(null, null);
-      packageManifest.libraries.add(new Reference.fromElement(libraryElement));
-      startFile("$revision/${libraryElement.id}.json");
-      write(json_serializer.serialize(libraryElement));
-      endFile();
-    }
-
-    startFile("$revision/apidoc.json");
-    write(json_serializer.serialize(packageManifest));
-    endFile();
-
-    // Write out top level json file with a relative path to the library json
-    // files.
-    startFile("apidoc.json");
-    packageManifest.location = revision;
-    write(json_serializer.serialize(packageManifest));
-    endFile();
-
-    _finished = true;
-  }
-
-  /**
-   * Generate [_hiddenLibraryExports] from [_exports].
-   */
-  Map<LibraryMirror, List<Export>> _generateHiddenLibraryExports() {
-    // First generate a map `exported library => exporter library => Export`.
-    // The inner map makes it easier to merge multiple exports of the same
-    // library by the same exporter.
-    var hiddenLibraryExportMaps =
-        new Map<LibraryMirror, Map<LibraryMirror, Export>>();
-
-    _exports.exports.forEach((exporter, exports) {
-      if (!shouldIncludeLibrary(exporter)) return;
-      for (var export in exports) {
-        var exported = export.exported;
-        if (shouldIncludeLibrary(exported)) continue;
-
-        var hiddenExports = _exports.transitiveExports(exported)
-            .map((transitiveExport) => export.compose(transitiveExport))
-            .toList();
-        hiddenExports.add(export);
-
-        for (var hiddenExport in hiddenExports) {
-          var exportsByExporter = hiddenLibraryExportMaps.putIfAbsent(
-              hiddenExport.exported, () => new Map<LibraryMirror, Export>());
-          addOrMergeExport(exportsByExporter, exporter, hiddenExport);
-        }
-      }
-    });
-
-    // Now sort the values of the inner maps of `hiddenLibraryExportMaps` to get
-    // the final value of `_hiddenLibraryExports`.
-    var hiddenLibraryExports = new Map<LibraryMirror, List<Export>>();
-    hiddenLibraryExportMaps.forEach((exportee, exportsByExporter) {
-      int rank(Export export) {
-        if (export.show.isEmpty && export.hide.isEmpty) return 0;
-        if (export.show.isEmpty) return export.hide.length;
-        // Multiply by 1000 to ensure this sorts after an export with hides.
-        return 1000 * export.show.length;
-      }
-
-      var exports = exportsByExporter.values.toList();
-      exports.sort((export1, export2) {
-        var comparison = Comparable.compare(rank(export1), rank(export2));
-        if (comparison != 0) return comparison;
-
-        var library1 = export1.exporter;
-        var library2 = export2.exporter;
-        return Comparable.compare(displayName(library1), displayName(library2));
-      });
-      hiddenLibraryExports[exportee] = exports;
-    });
-    return hiddenLibraryExports;
-  }
-
-  MdnComment lookupMdnComment(Mirror mirror) => null;
-
-  void startFile(String path) {
-    _filePath = path;
-    _file = new StringBuffer();
-  }
-
-  void endFile() {
-    final outPath = path.join(outputDir, _filePath);
-    final dir = new Directory(path.dirname(outPath));
-    if (!dir.existsSync()) {
-      // TODO(3914): Hack to avoid 'file already exists' exception
-      // thrown due to invalid result from dir.existsSync() (probably due to
-      // race conditions).
-      try {
-        dir.createSync();
-      } on FileSystemException catch (e) {
-        // Ignore.
-      }
-    }
-
-    writeString(new File(outPath), _file.toString());
-    _filePath = null;
-    _file = null;
-  }
-
-  void write(String s) {
-    _file.write(s);
-  }
-
-  void writeln(String s) {
-    write(s);
-    write('\n');
-  }
-
-  /**
-   * Writes the page header with the given [title] and [breadcrumbs]. The
-   * breadcrumbs are an interleaved list of links and titles. If a link is null,
-   * then no link will be generated. For example, given:
-   *
-   *     ['foo', 'foo.html', 'bar', null]
-   *
-   * It will output:
-   *
-   *     <a href="foo.html">foo</a> &rsaquo; bar
-   */
-  void writeHeader(String title, List<String> breadcrumbs) {
-    final htmlAttributes = generateAppCache ?
-        'manifest="/appcache.manifest"' : '';
-
-    write(
-        '''
-        <!DOCTYPE html>
-        <html${htmlAttributes == '' ? '' : ' $htmlAttributes'}>
-        <head>
-        ''');
-    writeHeadContents(title);
-
-    // Add data attributes describing what the page documents.
-    var data = '';
-    if (_currentLibrary != null) {
-      data = '$data data-library='
-             '"${md.escapeHtml(displayName(_currentLibrary))}"';
-    }
-
-    if (_currentType != null) {
-      data = '$data data-type="${md.escapeHtml(typeName(_currentType))}"';
-    }
-
-    write(
-        '''
-        </head>
-        <body$data>
-        <div class="page">
-        <div class="header">
-          ${a(mainUrl, '<div class="logo"></div>')}
-          ${a('index.html', mainTitle)}
-        ''');
-
-    // Write the breadcrumb trail.
-    for (int i = 0; i < breadcrumbs.length; i += 2) {
-      if (breadcrumbs[i + 1] == null) {
-        write(' &rsaquo; ${breadcrumbs[i]}');
-      } else {
-        write(' &rsaquo; ${a(breadcrumbs[i + 1], breadcrumbs[i])}');
-      }
-    }
-
-    if (searchEngineId != null) {
-      writeln(
-        '''
-        <form action="$searchResultsUrl" id="search-box">
-          <input type="hidden" name="cx" value="$searchEngineId">
-          <input type="hidden" name="ie" value="UTF-8">
-          <input type="hidden" name="hl" value="en">
-          <input type="search" name="q" id="q" autocomplete="off"
-              class="search-input" placeholder="Search API">
-        </form>
-        ''');
-    } else {
-      writeln(
-        '''
-        <div id="search-box">
-          <input type="search" name="q" id="q" autocomplete="off"
-              class="search-input" placeholder="Search API">
-        </div>
-        ''');
-    }
-
-    writeln(
-      '''
-      </div>
-      <div class="drop-down" id="drop-down"></div>
-      ''');
-
-    docNavigation();
-    writeln('<div class="content">');
-  }
-
-  String get clientScript {
-    switch (mode) {
-      case MODE_STATIC:   return 'client-static';
-      case MODE_LIVE_NAV: return 'client-live-nav';
-      default: throw 'Unknown mode $mode.';
-    }
-  }
-
-  void writeHeadContents(String title) {
-    writeln(
-        '''
-        <meta charset="utf-8">
-        <title>$title / $mainTitle</title>
-        <link rel="stylesheet" type="text/css"
-            href="${relativePath('styles.css')}">
-        <link href="//fonts.googleapis.com/css?family=Open+Sans:400,600,700,800" rel="stylesheet" type="text/css">
-        <link rel="shortcut icon" href="${relativePath('favicon.ico')}">
-        ''');
-  }
-
-  void writeFooter() {
-    writeln(
-        '''
-        </div>
-        <div class="clear"></div>
-        </div>
-        <div class="footer">
-          $footerContent
-        </div>
-        <script async src="${relativePath('$clientScript.js')}"></script>
-        </body></html>
-        ''');
-  }
-
-  void docIndex() {
-    startFile('index.html');
-
-    writeHeader(mainTitle, []);
-
-    writeln('<h2>$mainTitle</h2>');
-    writeln('<h3>Libraries</h3>');
-
-    for (final library in _sortedLibraries) {
-      docIndexLibrary(library);
-    }
-
-    writeFooter();
-    endFile();
-  }
-
-  void docIndexLibrary(LibraryMirror library) {
-    writeln('<h4>${a(libraryUrl(library), displayName(library))}</h4>');
-  }
-
-  /**
-   * Walks the libraries and creates a JSON object containing the data needed
-   * to generate navigation for them.
-   */
-  void docNavigationJson() {
-    startFile('nav.json');
-    writeln(JSON.encode(createNavigationInfo()));
-    endFile();
-  }
-  /// Whether dartdoc is running from within the Dart SDK or the
-  /// Dart source repository.
-  bool get runningFromSdk =>
-      path.extension(Platform.script.toFilePath()) == '.snapshot';
-
-  /// Gets the path to the root directory of the SDK.
-  String get sdkDir =>
-    path.dirname(path.dirname(Platform.executable));
-
-  /// Gets the path to the dartdoc directory normalized for running in different
-  /// places.
-  String get normalizedDartdocPath => path.normalize(
-      path.absolute(runningFromSdk ?
-          path.join(sdkDir, 'lib', '_internal', 'dartdoc') :
-          dartdocPath.toString()));
-
-  void docNavigationDart() {
-    var tmpDir = new Directory(tmpPath);
-    if (!tmpDir.existsSync()) {
-        tmpDir.createSync();
-    }
-    String jsonString = JSON.encode(createNavigationInfo());
-    String dartString = jsonString.replaceAll(r"$", r"\$");
-    var filePath = path.join(tmpPath, 'client.dart');
-
-    var clientDir = path.join(normalizedDartdocPath,'lib', 'src', 'client');
-
-    writeString(new File(filePath),
-        '''library client;
-        import 'dart:html';
-        import r'${path.toUri(path.join(clientDir, 'client-shared.dart'))}';
-        import r'${path.toUri(path.join(clientDir, 'dropdown.dart'))}';
-
-        main() {
-          setup();
-          setupSearch(json);
-        }
-
-        get json => $dartString;''');
-  }
-
-  void cleanup() {
-    var tmpDir = new Directory(tmpPath);
-    if (tmpDir.existsSync()) {
-      tmpDir.deleteSync(recursive: true);
-    }
-    tmpPath = null;
-  }
-
-  List createNavigationInfo() {
-    final libraryList = [];
-    for (final library in _sortedLibraries) {
-      docLibraryNavigationJson(library, libraryList);
-    }
-    return libraryList;
-  }
-
-  void docLibraryNavigationJson(LibraryMirror library, List libraryList) {
-    var libraryInfo = {};
-    libraryInfo[NAME] = displayName(library);
-    final List members = docMembersJson(library.members);
-    if (!members.isEmpty) {
-      libraryInfo[MEMBERS] = members;
-    }
-
-    final types = [];
-    for (ClassMirror type in orderByName(library.classes.values)) {
-      if (!showPrivate && type.isPrivate) continue;
-
-      var typeInfo = {};
-      typeInfo[NAME] = displayName(type);
-      if (type.isClass) {
-        typeInfo[KIND] = CLASS;
-      } else {
-        assert(type.isTypedef);
-        typeInfo[KIND] = TYPEDEF;
-      }
-      final List typeMembers = docMembersJson(type.members);
-      if (!typeMembers.isEmpty) {
-        typeInfo[MEMBERS] = typeMembers;
-      }
-
-      if (!type.originalDeclaration.typeVariables.isEmpty) {
-        final typeVariables = [];
-        for (final typeVariable in type.originalDeclaration.typeVariables) {
-          typeVariables.add(displayName(typeVariable));
-        }
-        typeInfo[ARGS] = typeVariables.join(', ');
-      }
-      types.add(typeInfo);
-    }
-    if (!types.isEmpty) {
-      libraryInfo[TYPES] = types;
-    }
-
-    libraryList.add(libraryInfo);
-  }
-
-  List docMembersJson(Map<Object,MemberMirror> memberMap) {
-    final members = [];
-    for (MemberMirror member in orderByName(memberMap.values)) {
-      if (!showPrivate && member.isPrivate) continue;
-
-      var memberInfo = {};
-      if (member.isVariable) {
-        memberInfo[KIND] = FIELD;
-      } else {
-        MethodMirror method = member;
-        if (method.isConstructor) {
-          memberInfo[KIND] = CONSTRUCTOR;
-        } else if (method.isSetter) {
-          memberInfo[KIND] = SETTER;
-        } else if (method.isGetter) {
-          memberInfo[KIND] = GETTER;
-        } else {
-          memberInfo[KIND] = METHOD;
-        }
-        if (method.parameters.isEmpty) {
-          memberInfo[NO_PARAMS] = true;
-        }
-      }
-      memberInfo[NAME] = displayName(member);
-      var anchor = memberAnchor(member);
-      if (anchor != memberInfo[NAME]) {
-        memberInfo[LINK_NAME] = anchor;
-      }
-      members.add(memberInfo);
-    }
-    return members;
-  }
-
-  void docNavigation() {
-    writeln(
-        '''
-        <div class="nav">
-        ''');
-
-    if (mode == MODE_STATIC) {
-      for (final library in _sortedLibraries) {
-        write('<h2><div class="icon-library"></div>');
-
-        if ((_currentLibrary == library) && (_currentType == null)) {
-          write('<strong>${displayName(library)}</strong>');
-        } else {
-          write('${a(libraryUrl(library), displayName(library))}');
-        }
-        write('</h2>');
-
-        // Only expand classes in navigation for current library.
-        if (_currentLibrary == library) docLibraryNavigation(library);
-      }
-    }
-
-    writeln('</div>');
-  }
-
-  /** Writes the navigation for the types contained by the given library. */
-  void docLibraryNavigation(LibraryMirror library) {
-    // Show the exception types separately.
-    final types = <ClassMirror>[];
-    final exceptions = <ClassMirror>[];
-
-    for (ClassMirror type in orderByName(library.classes.values)) {
-      if (!showPrivate && type.isPrivate) continue;
-
-      if (isException(type)) {
-        exceptions.add(type);
-      } else {
-        types.add(type);
-      }
-    }
-
-    if ((types.length == 0) && (exceptions.length == 0)) return;
-
-    writeln('<ul class="icon">');
-    types.forEach(docTypeNavigation);
-    exceptions.forEach(docTypeNavigation);
-    writeln('</ul>');
-  }
-
-  /** Writes a linked navigation list item for the given type. */
-  void docTypeNavigation(ClassMirror type) {
-    var icon = 'interface';
-    if (isException(type)) {
-      icon = 'exception';
-    } else if (type.isClass) {
-      icon = 'class';
-    }
-
-    write('<li>');
-    if (_currentType == type) {
-      write(
-          '<div class="icon-$icon"></div><strong>${typeName(type)}</strong>');
-    } else {
-      write(a(typeUrl(type),
-          '<div class="icon-$icon"></div>${typeName(type)}'));
-    }
-    writeln('</li>');
-  }
-
-  void docLibrary(LibraryMirror library) {
-    if (verbose) {
-      print('Library \'${displayName(library)}\':');
-    }
-    _totalLibraries++;
-    _currentLibrary = library;
-
-    startFile(libraryUrl(library));
-    writeHeader('${displayName(library)} Library',
-        [displayName(library), libraryUrl(library)]);
-    writeln('<h2><strong>${displayName(library)}</strong> library</h2>');
-
-    // Look for a comment for the entire library.
-    final comment = getLibraryComment(library);
-    if (comment != null) {
-      writeln('<div class="doc">${comment.html}</div>');
-    }
-
-    // Document the visible libraries exported by this library.
-    docExports(library);
-
-    // Document the top-level members.
-    docMembers(library);
-
-    // Document the types.
-    final abstractClasses = <ClassMirror>[];
-    final classes = <ClassMirror>[];
-    final typedefs = <TypedefMirror>[];
-    final exceptions = <ClassMirror>[];
-
-    var allClasses = _libraryClasses(library);
-    for (ClassMirror type in orderByName(allClasses)) {
-      if (!showPrivate && type.isPrivate) continue;
-
-      if (isException(type)) {
-        exceptions.add(type);
-      } else if (type.isClass) {
-        if (type.isAbstract) {
-          abstractClasses.add(type);
-        } else {
-          classes.add(type);
-        }
-      } else if (type is TypedefMirror) {
-        typedefs.add(type);
-      } else {
-        throw new InternalError("internal error: unknown type $type.");
-      }
-    }
-
-    docTypes(abstractClasses, 'Abstract Classes');
-    docTypes(classes, 'Classes');
-    docTypes(typedefs, 'Typedefs');
-    docTypes(exceptions, 'Exceptions');
-
-    writeFooter();
-    endFile();
-
-    for (final type in allClasses) {
-      if (!showPrivate && type.isPrivate) continue;
-
-      docType(type);
-    }
-
-    _currentLibrary = null;
-  }
-
-  void docTypes(List types, String header) {
-    if (types.length == 0) return;
-
-    writeln('<div>');
-    writeln('<h3>$header</h3>');
-
-    for (final type in types) {
-      writeln(
-          '''
-          <div class="type">
-          <h4>
-            ${a(typeUrl(type), "<strong>${typeName(type)}</strong>")}
-          </h4>
-          </div>
-          ''');
-    }
-    writeln('</div>');
-  }
-
-  void docType(ClassMirror type) {
-    if (verbose) {
-      print('- ${type.simpleName}');
-    }
-    _totalTypes++;
-    _currentType = type;
-
-    startFile(typePath(type));
-
-    var kind;
-    if (type.isTypedef) {
-      kind = 'typedef';
-    } else {
-      assert(type.isClass);
-      if (type.isAbstract) {
-        kind = 'abstract class';
-      } else {
-        kind = 'class';
-      }
-    }
-
-    final typeTitle =
-      '${typeName(type)} ${kind}';
-    var library = _libraryFor(type);
-    writeHeader('$typeTitle / ${displayName(library)} Library',
-        [displayName(library), libraryUrl(library),
-         typeName(type), typeUrl(type)]);
-    writeln(
-        '''
-        <h2><strong>${typeName(type, showBounds: true)}</strong>
-          $kind
-        </h2>
-        ''');
-    writeln('<button id="show-inherited" class="show-inherited">'
-            'Hide inherited</button>');
-
-    writeln('<div class="doc">');
-    docComment(type, getTypeComment(type));
-    docCode(type.location);
-    writeln('</div>');
-
-    docInheritance(type);
-    docTypedef(type);
-
-    docMembers(type);
-
-    writeTypeFooter();
-    writeFooter();
-    endFile();
-
-    _currentType = null;
-  }
-
-  /** Override this to write additional content at the end of a type's page. */
-  void writeTypeFooter() {
-    // Do nothing.
-  }
-
-  /**
-   * Writes an inline type span for the given type. This is a little box with
-   * an icon and the type's name. It's similar to how types appear in the
-   * navigation, but is suitable for inline (as opposed to in a `<ul>`) use.
-   */
-  void typeSpan(ClassMirror type) {
-    var icon = 'interface';
-    if (isException(type)) {
-      icon = 'exception';
-    } else if (type.isClass) {
-      icon = 'class';
-    }
-
-    write('<span class="type-box"><span class="icon-$icon"></span>');
-    if (_currentType == type) {
-      write('<strong>${typeName(type)}</strong>');
-    } else {
-      write(a(typeUrl(type), typeName(type)));
-    }
-    write('</span>');
-  }
-
-  /**
-   * Document the other types that touch [Type] in the inheritance hierarchy:
-   * subclasses, superclasses, subinterfaces, superinferfaces, and default
-   * class.
-   */
-  void docInheritance(ClassMirror type) {
-    // Don't show the inheritance details for Object. It doesn't have any base
-    // class (obviously) and it has too many subclasses to be useful.
-    if (type.isObject) return;
-    if (type.isTypedef) return;
-
-    // Writes an unordered list of references to types with an optional header.
-    listTypes(types, header) {
-      if (types == null) return;
-
-      // Filter out types from private dart libraries.
-      types = new List.from(types.where((t) => !isFromPrivateDartLibrary(t)));
-
-      var publicTypes;
-      if (showPrivate) {
-        publicTypes = types;
-      } else {
-        // Skip private types.
-        publicTypes = new List.from(types.where((t) => !t.isPrivate));
-      }
-      if (publicTypes.length == 0) return;
-
-      writeln('<h3>$header</h3>');
-      writeln('<p>');
-      bool first = true;
-      for (final t in publicTypes) {
-        if (!first) write(', ');
-        typeSpan(t);
-        first = false;
-      }
-      writeln('</p>');
-    }
-
-    final subtypes = [];
-    for (final subtype in computeSubdeclarations(type)) {
-      subtypes.add(subtype);
-    }
-    subtypes.sort((x, y) => x.simpleName.compareTo(y.simpleName));
-
-    // Show the chain of superclasses.
-    var superclass = getSuperclass(type);
-    if (!superclass.isObject) {
-      final supertypes = [];
-      var thisType = superclass;
-      do {
-        if (!isFromPrivateDartLibrary(thisType)) {
-          supertypes.add(thisType);
-        }
-        thisType = getSuperclass(thisType);
-      } while (!thisType.isObject);
-
-      writeln('<h3>Extends</h3>');
-      writeln('<p>');
-      for (var i = supertypes.length - 1; i >= 0; i--) {
-        typeSpan(supertypes[i]);
-        write('&nbsp;&gt;&nbsp;');
-      }
-
-      // Write this class.
-      typeSpan(type);
-      writeln('</p>');
-    }
-
-    listTypes(subtypes, 'Subclasses');
-    listTypes(getAppliedMixins(type), 'Mixins');
-    listTypes(getExplicitInterfaces(type), 'Implements');
-  }
-
-  /**
-   * Documents the definition of [type] if it is a typedef.
-   */
-  void docTypedef(TypeMirror type) {
-    if (type is! TypedefMirror) {
-      return;
-    }
-    writeln('<div class="method"><h4 id="${type.simpleName}">');
-
-    if (includeSource) {
-      writeln('<button class="show-code">Code</button>');
-    }
-
-    write('typedef ');
-    annotateType(type, type.value, type.simpleName);
-
-    write(''' <a class="anchor-link" href="#${type.simpleName}"
-              title="Permalink to ${type.simpleName}">#</a>''');
-    writeln('</h4>');
-
-    writeln('<div class="doc">');
-    docCode(type.location);
-    writeln('</div>');
-
-    writeln('</div>');
-  }
-
-  static const operatorOrder = const <String>[
-      '[]', '[]=', // Indexing.
-      '+', Mirror.UNARY_MINUS, '-', '*', '/', '~/', '%', // Arithmetic.
-      '&', '|', '^', '~', // Bitwise.
-      '<<', '>>', // Shift.
-      '<', '<=', '>', '>=', // Relational.
-      '==', // Equality.
-  ];
-
-  static final Map<String, int> operatorOrderMap = (){
-    var map = new Map<String, int>();
-    var index = 0;
-    for (String operator in operatorOrder) {
-      map[operator] = index++;
-    }
-    return map;
-  }();
-
-  void docExports(LibraryMirror library) {
-    var exportLinks = _exports.transitiveExports(library).map((export) {
-      var library = export.exported;
-      // Only link to publically visible libraries.
-      if (!shouldIncludeLibrary(library)) return null;
-
-      var memberNames = export.show.isEmpty ? export.hide : export.show;
-      var memberLinks = memberNames.map((name) {
-        return md.renderToHtml([resolveNameReference(
-            name, currentLibrary: library)]);
-      }).join(', ');
-      var combinator = '';
-      if (!export.show.isEmpty) {
-        combinator = ' show $memberLinks';
-      } else if (!export.hide.isEmpty) {
-        combinator = ' hide $memberLinks';
-      }
-
-      return '<ul>${a(libraryUrl(library), displayName(library))}'
-             '$combinator</ul>';
-    }).where((link) => link != null);
-
-    if (!exportLinks.isEmpty) {
-      writeln('<h3>Exports</h3>');
-      writeln('<ul>');
-      writeln(exportLinks.join('\n'));
-      writeln('</ul>');
-    }
-  }
-
-  void docMembers(ContainerMirror host) {
-    // Collect the different kinds of members.
-    final staticMethods = [];
-    final staticGetters = new Map<String,MemberMirror>();
-    final staticSetters = new Map<String,MemberMirror>();
-    final memberMap = new Map<String,MemberMirror>();
-    final instanceMethods = [];
-    final instanceOperators = [];
-    final instanceGetters = new Map<String,MemberMirror>();
-    final instanceSetters = new Map<String,MemberMirror>();
-    final constructors = [];
-
-    var hostMembers = host is LibraryMirror ?
-        _libraryMembers(host) : host.members.values;
-    for (var member in hostMembers) {
-      if (!showPrivate && member.isPrivate) continue;
-      if (host is LibraryMirror || member.isStatic) {
-        if (member is MethodMirror) {
-          if (member.isGetter) {
-            staticGetters[displayName(member)] = member;
-          } else if (member.isSetter) {
-            staticSetters[displayName(member)] = member;
-          } else {
-            staticMethods.add(member);
-          }
-        } else if (member is VariableMirror) {
-          staticGetters[displayName(member)] = member;
-        }
-      }
-    }
-
-    if (host is ClassMirror) {
-      var iterable = new HierarchyIterable(host, includeType: true);
-      for (ClassMirror type in iterable) {
-        if (!host.isObject && !inheritFromObject && type.isObject) continue;
-        if (isFromPrivateDartLibrary(type)) continue;
-
-        type.members.forEach((_, MemberMirror member) {
-          if (member.isStatic) return;
-          if (!showPrivate && member.isPrivate) return;
-
-          bool inherit = true;
-          if (type != host) {
-            if (member.isPrivate) {
-              // Don't inherit private members.
-              inherit = false;
-            }
-            if (member.isConstructor) {
-              // Don't inherit constructors.
-              inherit = false;
-            }
-          }
-          if (!inherit) return;
-
-          if (member.isVariable) {
-            // Fields override both getters and setters.
-            memberMap.putIfAbsent(member.simpleName, () => member);
-            memberMap.putIfAbsent('${member.simpleName}=', () => member);
-          } else if (member.isConstructor) {
-            constructors.add(member);
-          } else {
-            memberMap.putIfAbsent(member.simpleName, () => member);
-          }
-        });
-      }
-    }
-
-    bool allMethodsInherited = true;
-    bool allPropertiesInherited = true;
-    bool allOperatorsInherited = true;
-    memberMap.forEach((_, MemberMirror member) {
-      if (member is MethodMirror) {
-        if (member.isGetter) {
-          instanceGetters[displayName(member)] = member;
-          if (_ownerFor(member) == host) {
-            allPropertiesInherited = false;
-          }
-        } else if (member.isSetter) {
-          instanceSetters[displayName(member)] = member;
-          if (_ownerFor(member) == host) {
-            allPropertiesInherited = false;
-          }
-        } else if (member.isOperator) {
-          instanceOperators.add(member);
-          if (_ownerFor(member) == host) {
-            allOperatorsInherited = false;
-          }
-        } else {
-          instanceMethods.add(member);
-          if (_ownerFor(member) == host) {
-            allMethodsInherited = false;
-          }
-        }
-      } else if (member is VariableMirror) {
-        instanceGetters[displayName(member)] = member;
-        if (_ownerFor(member) == host) {
-          allPropertiesInherited = false;
-        }
-      }
-    });
-
-    instanceOperators.sort((MethodMirror a, MethodMirror b) {
-      return operatorOrderMap[a.simpleName].compareTo(
-          operatorOrderMap[b.simpleName]);
-    });
-
-    docProperties(host,
-                  host is LibraryMirror ? 'Properties' : 'Static Properties',
-                  staticGetters, staticSetters, allInherited: false);
-    docMethods(host,
-               host is LibraryMirror ? 'Functions' : 'Static Methods',
-               staticMethods, allInherited: false);
-
-    docMethods(host, 'Constructors', orderByName(constructors),
-               allInherited: false);
-    docProperties(host, 'Properties', instanceGetters, instanceSetters,
-                  allInherited: allPropertiesInherited);
-    docMethods(host, 'Operators', instanceOperators,
-               allInherited: allOperatorsInherited);
-    docMethods(host, 'Methods', orderByName(instanceMethods),
-               allInherited: allMethodsInherited);
-  }
-
-  /**
-   * Documents fields, getters, and setters as properties.
-   */
-  void docProperties(ContainerMirror host, String title,
-                     Map<String,MemberMirror> getters,
-                     Map<String,MemberMirror> setters,
-                     {bool allInherited}) {
-    if (getters.isEmpty && setters.isEmpty) return;
-
-    var nameSet = new Set<String>.from(getters.keys);
-    nameSet.addAll(setters.keys);
-    var nameList = new List<String>.from(nameSet);
-    nameList.sort((String a, String b) {
-      return a.toLowerCase().compareTo(b.toLowerCase());
-    });
-
-    writeln('<div${allInherited ? ' class="inherited"' : ''}>');
-    writeln('<h3>$title</h3>');
-    for (String name in nameList) {
-      MemberMirror getter = getters[name];
-      MemberMirror setter = setters[name];
-      if (setter == null) {
-        if (getter is VariableMirror) {
-          // We have a field.
-          docField(host, getter);
-        } else {
-          // We only have a getter.
-          assert(getter is MethodMirror);
-          docProperty(host, getter, null);
-        }
-      } else if (getter == null) {
-        // We only have a setter => Document as a method.
-        assert(setter is MethodMirror);
-        docMethod(host, setter);
-      } else {
-        DocComment getterComment = getMemberComment(getter);
-        DocComment setterComment = getMemberComment(setter);
-        if (_ownerFor(getter) != _ownerFor(setter) ||
-            getterComment != null && setterComment != null) {
-          // Both have comments or are not declared in the same class
-          // => Documents separately.
-          if (getter is VariableMirror) {
-            // Document field as a getter (setter is inherited).
-            docField(host, getter, asGetter: true);
-          } else {
-            docMethod(host, getter);
-          }
-          if (setter is VariableMirror) {
-            // Document field as a setter (getter is inherited).
-            docField(host, setter, asSetter: true);
-          } else {
-            docMethod(host, setter);
-          }
-        } else {
-          // Document as field.
-          docProperty(host, getter, setter);
-        }
-      }
-    }
-    writeln('</div>');
-  }
-
-  void docMethods(ContainerMirror host, String title, List<Mirror> methods,
-                  {bool allInherited}) {
-    if (methods.length > 0) {
-      writeln('<div${allInherited ? ' class="inherited"' : ''}>');
-      writeln('<h3>$title</h3>');
-      for (MethodMirror method in methods) {
-        docMethod(host, method);
-      }
-      writeln('</div>');
-    }
-  }
-
-  /**
-   * Documents the [member] declared in [host]. Handles all kinds of members
-   * including getters, setters, and constructors. If [member] is a
-   * [FieldMirror] it is documented as a getter or setter depending upon the
-   * value of [asGetter].
-   */
-  void docMethod(ContainerMirror host, MemberMirror member,
-                 {bool asGetter: false}) {
-    _totalMembers++;
-    _currentMember = member;
-
-    bool isAbstract = false;
-    String name = displayName(member);
-    if (member is VariableMirror) {
-      if (asGetter) {
-        // Getter.
-        name = 'get $name';
-      } else {
-        // Setter.
-        name = 'set $name';
-      }
-    } else {
-      assert(member is MethodMirror);
-      isAbstract = member.isAbstract;
-      if (member.isGetter) {
-        // Getter.
-        name = 'get $name';
-      } else if (member.isSetter) {
-        // Setter.
-        name = 'set $name';
-      }
-    }
-
-    bool showCode = includeSource && !isAbstract;
-    bool inherited = host != member.owner && member.owner is! LibraryMirror;
-
-    writeln('<div class="method${inherited ? ' inherited': ''}">'
-            '<h4 id="${memberAnchor(member)}">');
-
-    if (showCode) {
-      writeln('<button class="show-code">Code</button>');
-    }
-
-    if (member is MethodMirror) {
-      if (member.isConstructor) {
-        if (member.isFactoryConstructor) {
-          write('factory ');
-        } else {
-          write(member.isConstConstructor ? 'const ' : 'new ');
-        }
-      } else if (member.isAbstract) {
-        write('abstract ');
-      }
-
-      if (!member.isConstructor) {
-        annotateDynamicType(host, member.returnType);
-      }
-    } else {
-      assert(member is VariableMirror);
-      if (asGetter) {
-        annotateDynamicType(host, member.type);
-      } else {
-        write('void ');
-      }
-    }
-
-    write('<strong>$name</strong>');
-
-    if (member is MethodMirror) {
-      if (!member.isGetter) {
-        docParamList(host, member.parameters);
-      }
-    } else {
-      assert(member is VariableMirror);
-      if (!asGetter) {
-        write('(');
-        annotateType(host, member.type);
-        write(' value)');
-      }
-    }
-
-    var prefix = host is LibraryMirror ? '' : '${typeName(host)}.';
-    write(''' <a class="anchor-link" href="#${memberAnchor(member)}"
-              title="Permalink to $prefix$name">#</a>''');
-    writeln('</h4>');
-
-    if (inherited) {
-      docInherited(host, member.owner);
-    }
-
-    writeln('<div class="doc">');
-    docComment(host, getMemberComment(member));
-    if (showCode) {
-      docCode(member.location);
-    }
-    writeln('</div>');
-
-    writeln('</div>');
-
-    _currentMember = null;
-  }
-
-  /**
-   * Annotate a member as inherited or mixed in from [owner].
-   */
-  void docInherited(ContainerMirror host, ClassMirror owner) {
-    if (isMixinApplication(owner)) {
-      write('<div class="inherited-from">mixed in from ');
-      annotateType(host, owner.mixin);
-      write('</div>');
-    } else {
-      write('<div class="inherited-from">inherited from ');
-      annotateType(host, owner);
-      write('</div>');
-    }
-  }
-
-  void docField(ContainerMirror host, VariableMirror field,
-                {bool asGetter: false, bool asSetter: false}) {
-    if (asGetter) {
-      docMethod(host, field, asGetter: true);
-    } else if (asSetter) {
-      docMethod(host, field, asGetter: false);
-    } else {
-      docProperty(host, field, null);
-    }
-  }
-
-  /**
-   * Documents the property defined by [getter] and [setter] of declared in
-   * [host]. If [getter] is a [FieldMirror], [setter] must be [:null:].
-   * Otherwise, if [getter] is a [MethodMirror], the property is considered
-   * final if [setter] is [:null:].
-   */
-  void docProperty(ContainerMirror host,
-                   MemberMirror getter, MemberMirror setter) {
-    assert(getter != null);
-    _totalMembers++;
-    _currentMember = getter;
-
-    bool inherited = host != getter.owner && getter.owner is! LibraryMirror;
-
-    writeln('<div class="field${inherited ? ' inherited' : ''}">'
-            '<h4 id="${memberAnchor(getter)}">');
-
-    if (includeSource) {
-      writeln('<button class="show-code">Code</button>');
-    }
-
-    bool isConst = false;
-    bool isFinal;
-    TypeMirror type;
-    if (getter is VariableMirror) {
-      assert(setter == null);
-      isConst = getter.isConst;
-      isFinal = getter.isFinal;
-      type = getter.type;
-    } else {
-      assert(getter is MethodMirror);
-      isFinal = setter == null;
-      type = getter.returnType;
-    }
-
-    if (isConst) {
-      write('const ');
-    } else if (isFinal) {
-      write('final ');
-    } else if (type.isDynamic) {
-      write('var ');
-    }
-
-    annotateType(host, type);
-    var prefix = host is LibraryMirror ? '' : '${typeName(host)}.';
-    write(
-        '''
-        <strong>${getter.simpleName}</strong> <a class="anchor-link"
-            href="#${memberAnchor(getter)}"
-            title="Permalink to $prefix${getter.simpleName}">#</a>
-        </h4>
-        ''');
-
-    if (inherited) {
-      docInherited(host, getter.owner);
-    }
-
-    DocComment comment = getMemberComment(getter);
-    if (comment == null && setter != null) {
-      comment = getMemberComment(setter);
-    }
-    writeln('<div class="doc">');
-    docComment(host, comment);
-    docCode(getter.location);
-    if (setter != null) {
-      docCode(setter.location);
-    }
-    writeln('</div>');
-
-    writeln('</div>');
-
-    _currentMember = null;
-  }
-
-  void docParamList(ContainerMirror enclosingType,
-                    List<ParameterMirror> parameters) {
-    write('(');
-    bool first = true;
-    bool inOptionals = false;
-    bool isNamed = false;
-    for (final parameter in parameters) {
-      if (!first) write(', ');
-
-      if (!inOptionals && parameter.isOptional) {
-        isNamed = parameter.isNamed;
-        write(isNamed ? '{' : '[');
-        inOptionals = true;
-      }
-
-      annotateType(enclosingType, parameter.type, parameter.simpleName);
-
-      // Show the default value for named optional parameters.
-      if (parameter.isOptional && parameter.hasDefaultValue) {
-        write(isNamed ? ': ' : ' = ');
-        write(parameter.defaultValue);
-      }
-
-      first = false;
-    }
-
-    if (inOptionals) {
-      write(isNamed ? '}' : ']');
-    }
-    write(')');
-  }
-
-  void docComment(ContainerMirror host, DocComment comment) {
-    if (comment != null) {
-      var html = comment.html;
-
-      if (comment.inheritedFrom != null) {
-        writeln('<div class="inherited">');
-        writeln(html);
-        write('<div class="docs-inherited-from">docs inherited from ');
-        annotateType(host, comment.inheritedFrom);
-        write('</div>');
-        writeln('</div>');
-      } else {
-        writeln(html);
-      }
-    }
-  }
-
-  /**
-   * Documents the source code contained within [location].
-   */
-  void docCode(SourceLocation location) {
-    if (includeSource) {
-      writeln('<pre class="source">');
-      writeln(md.escapeHtml(unindentCode(location)));
-      writeln('</pre>');
-    }
-  }
-
-  /** Get the doc comment associated with the given library. */
-  DocComment getLibraryComment(LibraryMirror library) => getComment(library);
-
-  /** Get the doc comment associated with the given type. */
-  DocComment getTypeComment(TypeMirror type) => getComment(type);
-
-  /**
-   * Get the doc comment associated with the given member.
-   *
-   * If no comment was found on the member, the hierarchy is traversed to find
-   * an inherited comment, favouring comments inherited from classes over
-   * comments inherited from interfaces.
-   */
-  DocComment getMemberComment(MemberMirror member) => getComment(member);
-
-  /**
-   * Get the doc comment associated with the given declaration.
-   *
-   * If no comment was found on a member, the hierarchy is traversed to find
-   * an inherited comment, favouring comments inherited from classes over
-   * comments inherited from interfaces.
-   */
-  DocComment getComment(DeclarationMirror mirror) {
-    String comment = computeComment(mirror);
-    ClassMirror inheritedFrom = null;
-    if (comment == null) {
-      if (mirror.owner is ClassMirror) {
-        var iterable =
-            new HierarchyIterable(mirror.owner,
-                                  includeType: false);
-        for (ClassMirror type in iterable) {
-          if (isFromPrivateDartLibrary(type)) continue;
-          var inheritedMember = type.members[mirror.simpleName];
-          if (inheritedMember is MemberMirror) {
-            comment = computeComment(inheritedMember);
-            if (comment != null) {
-              inheritedFrom = type;
-              break;
-            }
-          }
-        }
-      }
-    }
-    if (comment == null) return null;
-    if (isMixinApplication(inheritedFrom)) {
-      inheritedFrom = inheritedFrom.mixin;
-    }
-    return new DocComment(comment, inheritedFrom, dartdocSyntaxes,
-        dartdocResolver);
-  }
-
-  /**
-   * Converts [fullPath] which is understood to be a full path from the root of
-   * the generated docs to one relative to the current file.
-   */
-  String relativePath(String fullPath) {
-    // Don't make it relative if it's an absolute path.
-    if (isAbsolute(fullPath)) return fullPath;
-
-    // TODO(rnystrom): Walks all the way up to root each time. Shouldn't do
-    // this if the paths overlap.
-    return '${repeat('../',
-                     countOccurrences(_filePath.toString(), '/'))}$fullPath';
-  }
-
-  /** Gets whether or not the given URL is absolute or relative. */
-  bool isAbsolute(String url) {
-    // TODO(rnystrom): Why don't we have a nice type in the platform for this?
-    // TODO(rnystrom): This is a bit hackish. We consider any URL that lacks
-    // a scheme to be relative.
-    return new RegExp(r'^\w+:').hasMatch(url);
-  }
-
-  /** Gets the URL to the documentation for [library]. */
-  String libraryUrl(LibraryMirror library) {
-    return '${sanitize(displayName(library))}.html';
-  }
-
-  /**
-   * Gets the URL for the documentation for [type] or `null` if there is no
-   * link to the documentation of [type].
-   */
-  String typeUrl(ContainerMirror type) {
-    var library = type is LibraryMirror ? type : _libraryFor(type);
-    if (shouldLinkToPublicApi(library)) {
-      return "$API_LOCATION${typePath(type)}";
-    } else if (shouldIncludeLibrary(library)) {
-      return typePath(type);
-    } else {
-      return null;
-    }
-  }
-
-  /** Gets the relative path for the documentation for [type]. */
-  String typePath(ContainerMirror type) {
-    if (type is LibraryMirror) {
-      return '${sanitize(type.simpleName)}.html';
-    }
-    if (type.library == null) {
-      return '';
-    }
-    // Always get the generic type to strip off any type parameters or
-    // arguments. If the type isn't generic, genericType returns `this`, so it
-    // works for non-generic types too.
-    return '${sanitize(displayName(_libraryFor(type)))}/'
-           '${type.originalDeclaration.simpleName}.html';
-  }
-
-  /** Gets the URL for the documentation for [member]. */
-  String memberUrl(MemberMirror member) {
-    String url = typeUrl(_ownerFor(member));
-    return url != null ? '$url#${memberAnchor(member)}' : null;
-  }
-
-  /** Gets the anchor id for the document for [member]. */
-  String memberAnchor(MemberMirror member) {
-    return member.simpleName;
-  }
-
-  /**
-   * Creates a hyperlink. Handles turning the [href] into an appropriate
-   * relative path from the current file. If [href] is `null`, [contents] is
-   * not embedded in an anchor tag, and thus no link is created.
-   */
-  String a(String href, String contents, [String css]) {
-    if (href != null) {
-      // Mark outgoing external links, mainly so we can style them.
-      final rel = isAbsolute(href) ? ' ref="external"' : '';
-      final cssClass = css == null ? '' : ' class="$css"';
-      return '<a href="${relativePath(href)}"$cssClass$rel>$contents</a>';
-    }
-    return contents;
-  }
-
-  /**
-   * Writes a type annotation, preferring to print dynamic.
-   */
-  annotateDynamicType(ContainerMirror enclosingType,
-                      TypeMirror type) {
-    annotateType(enclosingType, type, type.isDynamic ? 'dynamic ' : null);
-  }
-
-  /**
-   * Writes a type annotation for the given type and (optional) parameter name.
-   */
-  annotateType(ContainerMirror enclosingType,
-               TypeMirror type,
-               [String paramName = null]) {
-    // Don't bother explicitly displaying dynamic.
-    if (type.isDynamic) {
-      if (paramName != null) write(paramName);
-      return;
-    }
-
-    // For parameters, handle non-typedefed function types.
-    if (paramName != null && type is FunctionTypeMirror) {
-      annotateType(enclosingType, type.returnType);
-      write(paramName);
-
-      docParamList(enclosingType, type.parameters);
-      return;
-    }
-
-    linkToType(enclosingType, type);
-
-    write(' ');
-    if (paramName != null) write(paramName);
-  }
-
-  /** Writes a link to a human-friendly string representation for a type. */
-  linkToType(ContainerMirror enclosingType, TypeMirror type) {
-    if (type.isVoid) {
-      // Do not generate links for void.
-      // TODO(johnniwinter): Generate span for specific style?
-      write('void');
-      return;
-    }
-    if (type.isDynamic) {
-      // Do not generate links for dynamic.
-      write('dynamic');
-      return;
-    }
-
-    if (type.isTypeVariable) {
-      // If we're using a type parameter within the body of a generic class then
-      // just link back up to the class.
-      write(a(typeUrl(enclosingType), type.simpleName));
-      return;
-    }
-
-    assert(type is ClassMirror);
-
-    // Link to the type.
-    write(a(typeUrl(type), type.simpleName));
-
-    if (type.isOriginalDeclaration) {
-      // Avoid calling [:typeArguments():] on a declaration.
-      return;
-    }
-
-    // See if it's an instantiation of a generic type.
-    final typeArgs = type.typeArguments;
-    if (typeArgs.length > 0) {
-      write('&lt;');
-      bool first = true;
-      for (final arg in typeArgs) {
-        if (!first) write(', ');
-        first = false;
-        linkToType(enclosingType, arg);
-      }
-      write('&gt;');
-    }
-  }
-
-  /** Creates a linked cross reference to [type]. */
-  typeReference(ClassMirror type) {
-    // TODO(rnystrom): Do we need to handle ParameterTypes here like
-    // annotation() does?
-    return a(typeUrl(type), typeName(type), 'crossref');
-  }
-
-  /** Generates a human-friendly string representation for a type. */
-  typeName(TypeMirror type, {bool showBounds: false}) {
-    if (type.isVoid) {
-      return 'void';
-    }
-    if (type.isDynamic) {
-      return 'dynamic';
-    }
-    if (type is TypeVariableMirror) {
-      return type.simpleName;
-    }
-    assert(type is ClassMirror);
-
-    // See if it's a generic type.
-    if (type.isOriginalDeclaration) {
-      final typeParams = [];
-      for (final typeParam in type.originalDeclaration.typeVariables) {
-        if (showBounds &&
-            (typeParam.upperBound != null) &&
-            !typeParam.upperBound.isObject) {
-          final bound = typeName(typeParam.upperBound, showBounds: true);
-          typeParams.add('${typeParam.simpleName} extends $bound');
-        } else {
-          typeParams.add(typeParam.simpleName);
-        }
-      }
-      if (typeParams.isEmpty) {
-        return type.simpleName;
-      }
-      final params = typeParams.join(', ');
-      return '${type.simpleName}&lt;$params&gt;';
-    }
-
-    // See if it's an instantiation of a generic type.
-    final typeArgs = type.typeArguments;
-    if (typeArgs.length > 0) {
-      final args = typeArgs.map((arg) => typeName(arg)).join(', ');
-      return '${type.originalDeclaration.simpleName}&lt;$args&gt;';
-    }
-
-    // Regular type.
-    return type.simpleName;
-  }
-
-  /**
-   * Remove leading indentation to line up with first line.
-   */
-  unindentCode(SourceLocation span) {
-    final column = span.column;
-    final lines = span.text.split('\n');
-    // TODO(rnystrom): Dirty hack.
-    for (var i = 1; i < lines.length; i++) {
-      lines[i] = unindent(lines[i], column);
-    }
-
-    final code = lines.join('\n');
-    return code;
-  }
-
-  /**
-   * Takes a string of Dart code and turns it into sanitized HTML.
-   */
-  formatCode(SourceLocation span) {
-    final code = unindentCode(span);
-
-    // Syntax highlight.
-    return classifySource(code);
-  }
-
-  /**
-   * This will be called whenever a doc comment hits a `[name]` in square
-   * brackets. It will try to figure out what the name refers to and link or
-   * style it appropriately.
-   */
-  md.Node resolveNameReference(String name,
-                               {MemberMirror currentMember,
-                                ContainerMirror currentType,
-                                LibraryMirror currentLibrary}) {
-    makeLink(String href) {
-      if (href != null) {
-        final anchor = new md.Element.text('a', name);
-        anchor.attributes['href'] = relativePath(href);
-        anchor.attributes['class'] = 'crossref';
-        return anchor;
-      } else {
-        return new md.Element.text('code', name);
-      }
-    }
-
-    DeclarationMirror declaration = currentMember;
-    if (declaration == null) declaration = currentType;
-    if (declaration == null) declaration = currentLibrary;
-    if (declaration != null) {
-      declaration = lookupQualifiedInScope(declaration, name);
-    }
-
-    if (declaration != null) {
-      if (declaration is TypeVariableMirror) {
-        return makeLink(typeUrl(declaration.owner));
-      } if (declaration is TypeMirror) {
-        return makeLink(typeUrl(declaration));
-      } else if (declaration is MethodMirror) {
-        return makeLink(memberUrl(declaration));
-      }
-    }
-
-    // See if it's a parameter of the current method.
-    if (currentMember is MethodMirror) {
-      for (final parameter in currentMember.parameters) {
-        if (parameter.simpleName == name) {
-          final element = new md.Element.text('span', name);
-          element.attributes['class'] = 'param';
-          return element;
-        }
-      }
-    }
-
-    // See if it's another member of the current type.
-    if (currentType != null) {
-      final foundMember = currentType.members[name];
-      if (foundMember != null) {
-        return makeLink(memberUrl(foundMember));
-      }
-    }
-
-    // See if it's another type or a member of another type in the current
-    // library.
-    if (currentLibrary != null) {
-      // See if it's a constructor
-      final constructorLink = (() {
-        final match =
-            new RegExp(r'new ([\w$]+)(?:\.([\w$]+))?').firstMatch(name);
-        if (match == null) return;
-        String typeName = match[1];
-        ClassMirror foundtype = currentLibrary.classes[typeName];
-        if (foundtype == null) return;
-        String constructorName =
-            (match[2] == null) ? typeName : '$typeName.${match[2]}';
-        final constructor =
-            foundtype.constructors[constructorName];
-        if (constructor == null) return;
-        return makeLink(memberUrl(constructor));
-      })();
-      if (constructorLink != null) return constructorLink;
-
-      // See if it's a member of another type
-      final foreignMemberLink = (() {
-        final match = new RegExp(r'([\w$]+)\.([\w$]+)').firstMatch(name);
-        if (match == null) return;
-        ClassMirror foundtype = currentLibrary.classes[match[1]];
-        if (foundtype == null) return;
-        MemberMirror foundMember = foundtype.members[match[2]];
-        if (foundMember == null) return;
-        return makeLink(memberUrl(foundMember));
-      })();
-      if (foreignMemberLink != null) return foreignMemberLink;
-
-      ClassMirror foundType = currentLibrary.classes[name];
-      if (foundType != null) {
-        return makeLink(typeUrl(foundType));
-      }
-
-      // See if it's a top-level member in the current library.
-      MemberMirror foundMember = currentLibrary.members[name];
-      if (foundMember != null) {
-        return makeLink(memberUrl(foundMember));
-      }
-    }
-
-    // TODO(rnystrom): Should also consider:
-    // * Names imported by libraries this library imports.
-    // * Type parameters of the enclosing type.
-
-    return new md.Element.text('code', name);
-  }
-
-  generateAppCacheManifest() {
-    if (verbose) {
-      print('Generating app cache manifest from output $outputDir');
-    }
-    startFile('appcache.manifest');
-    write("CACHE MANIFEST\n\n");
-    write("# VERSION: ${new DateTime.now()}\n\n");
-    write("NETWORK:\n*\n\n");
-    write("CACHE:\n");
-    var toCache = new Directory(outputDir);
-    toCache.list(recursive: true).listen(
-        (FileSystemEntity entity) {
-          if (entity is File) {
-            var filename = entity.path;
-            if (filename.endsWith('appcache.manifest')) {
-              return;
-            }
-            String relativeFilePath = path.relative(filename, from: outputDir);
-            write("$relativeFilePath\n");
-          }
-        },
-        onDone: () => endFile());
-  }
-
-  /**
-   * Returns [:true:] if [type] should be regarded as an exception.
-   */
-  bool isException(TypeMirror type) {
-    return type.simpleName.endsWith('Exception') ||
-        type.simpleName.endsWith('Error');
-  }
-
-  /**
-   * Returns the absolute path to [library] on the filesystem, or `null` if the
-   * library doesn't exist on the local filesystem.
-   */
-  String _libraryPath(LibraryMirror library) =>
-    importUriToPath(library.uri, packageRoot: _packageRoot);
-
-  /**
-   * Returns a list of classes in [library], including classes it exports from
-   * hidden libraries.
-   */
-  List<ClassMirror> _libraryClasses(LibraryMirror library) =>
-    _libraryContents(library, (lib) => lib.classes.values);
-
-  /**
-   * Returns a list of top-level members in [library], including members it
-   * exports from hidden libraries.
-   */
-  List<MemberMirror> _libraryMembers(LibraryMirror library) =>
-    _libraryContents(library, (lib) => lib.members.values);
-
-
-  /**
-   * Returns a list of elements in [library], including elements it exports from
-   * hidden libraries. [fn] should return the element list for a single library,
-   * which will then be merged across all exported libraries.
-   */
-  List<DeclarationMirror> _libraryContents(LibraryMirror library,
-      List<DeclarationMirror> fn(LibraryMirror)) {
-    var contents = fn(library).toList();
-    var exports = _exports.exports[library];
-    if (exports == null) return contents;
-
-    contents.addAll(exports.expand((export) {
-      var exportedLibrary = export.exported;
-      if (shouldIncludeLibrary(exportedLibrary)) return [];
-      return fn(exportedLibrary).where((declaration) =>
-          export.isMemberVisible(displayName(declaration)));
-    }));
-    return contents;
-  }
-
-  /**
-   * Returns the library in which [type] was defined. If [type] was defined in a
-   * hidden library that was exported by another library, this returns the
-   * exporter.
-   */
-  LibraryMirror _libraryFor(TypeMirror type) =>
-    _visibleLibrary(type.library, displayName(type));
-
-  /**
-   * Returns the owner of [declaration]. If [declaration]'s owner is a hidden
-   * library that was exported by another library, this returns the exporter.
-   */
-  DeclarationMirror _ownerFor(DeclarationMirror declaration) {
-    var owner = declaration.owner;
-    if (owner is! LibraryMirror) return owner;
-    return _visibleLibrary(owner, displayName(declaration));
-  }
-
-  /**
-   * Returns the best visible library that exports [name] from [library]. If
-   * [library] is public, it will be returned.
-   */
-  LibraryMirror _visibleLibrary(LibraryMirror library, String name) {
-    if (library == null) return null;
-
-    var exports = _hiddenLibraryExports[library];
-    if (exports == null) return library;
-
-    var export = exports.firstWhere(
-        (exp) => exp.isMemberVisible(name),
-        orElse: () => null);
-    if (export == null) return library;
-    return export.exporter;
-  }
-}
-
-/**
- * Used to report an unexpected error in the DartDoc tool or the
- * underlying data
- */
-class InternalError {
-  final String message;
-  const InternalError(this.message);
-  String toString() => "InternalError: '$message'";
-}
-
-/**
- * Computes the doc comment for the declaration mirror.
- *
- * Multiple comments are concatenated with newlines in between.
- */
-String computeComment(DeclarationMirror mirror) {
-  String text;
-  for (InstanceMirror metadata in mirror.metadata) {
-    if (metadata is CommentInstanceMirror) {
-      CommentInstanceMirror comment = metadata;
-      if (comment.isDocComment) {
-        if (text == null) {
-          text = comment.trimmedText;
-        } else {
-          text = '$text\n${comment.trimmedText}';
-        }
-      }
-    }
-  }
-  return text;
-}
-
-/**
- * Computes the doc comment for the declaration mirror as a list.
- */
-List<String> computeUntrimmedCommentAsList(DeclarationMirror mirror) {
-  var text = <String>[];
-  for (InstanceMirror metadata in mirror.metadata) {
-    if (metadata is CommentInstanceMirror) {
-      CommentInstanceMirror comment = metadata;
-      if (comment.isDocComment) {
-        text.add(comment.text);
-      }
-    }
-  }
-  return text;
-}
-
-class DocComment {
-  final String text;
-  md.Resolver dartdocResolver;
-  List<md.InlineSyntax> dartdocSyntaxes;
-
-  /**
-   * Non-null if the comment is inherited from another declaration.
-   */
-  final ClassMirror inheritedFrom;
-
-  DocComment(this.text, [this.inheritedFrom = null, this.dartdocSyntaxes,
-      this.dartdocResolver]) {
-    assert(text != null && !text.trim().isEmpty);
-  }
-
-  String toString() => text;
-
-  String get html {
-    return md.markdownToHtml(text,
-        inlineSyntaxes: dartdocSyntaxes,
-        linkResolver: dartdocResolver);
-  }
-}
-
-class MdnComment implements DocComment {
-  final String mdnComment;
-  final String mdnUrl;
-
-  MdnComment(String this.mdnComment, String this.mdnUrl);
-
-  String get text => mdnComment;
-
-  ClassMirror get inheritedFrom => null;
-
-  String get html {
-    // Wrap the mdn comment so we can highlight it and so we handle MDN scraped
-    // content that lacks a top-level block tag.
-   return '''
-        <div class="mdn">
-        $mdnComment
-        <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div>
-        </div>
-        ''';
-  }
-
-  String toString() => mdnComment;
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/markdown.dart b/sdk/lib/_internal/dartdoc/lib/markdown.dart
deleted file mode 100644
index 01de970..0000000
--- a/sdk/lib/_internal/dartdoc/lib/markdown.dart
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/// Parses text in a markdown-like format and renders to HTML.
-library markdown;
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-part 'src/markdown/ast.dart';
-part 'src/markdown/block_parser.dart';
-part 'src/markdown/html_renderer.dart';
-part 'src/markdown/inline_parser.dart';
-
-typedef Node Resolver(String name);
-
-/// Converts the given string of markdown to HTML.
-String markdownToHtml(String markdown, {inlineSyntaxes, linkResolver}) {
-  final document = new Document(inlineSyntaxes: inlineSyntaxes,
-      linkResolver: linkResolver);
-
-  // Replace windows line endings with unix line endings, and split.
-  final lines = markdown.replaceAll('\r\n','\n').split('\n');
-  document.parseRefLinks(lines);
-  final blocks = document.parseLines(lines);
-  return renderToHtml(blocks);
-}
-
-/// Replaces `<`, `&`, and `>`, with their HTML entity equivalents.
-String escapeHtml(String html) {
-  return html.replaceAll('&', '&amp;')
-             .replaceAll('<', '&lt;')
-             .replaceAll('>', '&gt;');
-}
-
-/// Maintains the context needed to parse a markdown document.
-class Document {
-  final Map<String, Link> refLinks;
-  List<InlineSyntax> inlineSyntaxes;
-  Resolver linkResolver;
-
-  Document({this.inlineSyntaxes, this.linkResolver})
-    : refLinks = <String, Link>{};
-
-  parseRefLinks(List<String> lines) {
-    // This is a hideous regex. It matches:
-    // [id]: http:foo.com "some title"
-    // Where there may whitespace in there, and where the title may be in
-    // single quotes, double quotes, or parentheses.
-    final indent = r'^[ ]{0,3}'; // Leading indentation.
-    final id = r'\[([^\]]+)\]';  // Reference id in [brackets].
-    final quote = r'"[^"]+"';    // Title in "double quotes".
-    final apos = r"'[^']+'";     // Title in 'single quotes'.
-    final paren = r"\([^)]+\)";  // Title in (parentheses).
-    final pattern = new RegExp(
-        '$indent$id:\\s+(\\S+)\\s*($quote|$apos|$paren|)\\s*\$');
-
-    for (int i = 0; i < lines.length; i++) {
-      final match = pattern.firstMatch(lines[i]);
-      if (match != null) {
-        // Parse the link.
-        var id = match[1];
-        var url = match[2];
-        var title = match[3];
-
-        if (title == '') {
-          // No title.
-          title = null;
-        } else {
-          // Remove "", '', or ().
-          title = title.substring(1, title.length - 1);
-        }
-
-        // References are case-insensitive.
-        id = id.toLowerCase();
-
-        refLinks[id] = new Link(id, url, title);
-
-        // Remove it from the output. We replace it with a blank line which will
-        // get consumed by later processing.
-        lines[i] = '';
-      }
-    }
-  }
-
-  /// Parse the given [lines] of markdown to a series of AST nodes.
-  List<Node> parseLines(List<String> lines) {
-    final parser = new BlockParser(lines, this);
-
-    final blocks = [];
-    while (!parser.isDone) {
-      for (final syntax in BlockSyntax.syntaxes) {
-        if (syntax.canParse(parser)) {
-          final block = syntax.parse(parser);
-          if (block != null) blocks.add(block);
-          break;
-        }
-      }
-    }
-
-    return blocks;
-  }
-
-  /// Takes a string of raw text and processes all inline markdown tags,
-  /// returning a list of AST nodes. For example, given ``"*this **is** a*
-  /// `markdown`"``, returns:
-  /// `<em>this <strong>is</strong> a</em> <code>markdown</code>`.
-  List<Node> parseInline(String text) => new InlineParser(text, this).parse();
-}
-
-class Link {
-  final String id;
-  final String url;
-  final String title;
-  Link(this.id, this.url, this.title);
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
deleted file mode 100644
index 958fcb1..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
+++ /dev/null
@@ -1,97 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/** Provides client-side behavior for generated docs. */
-library client;
-
-import 'dart:html';
-import 'dart:convert';
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../../classify.dart';
-import '../../markdown.dart' as md;
-import '../dartdoc/nav.dart';
-import 'dropdown.dart';
-import 'search.dart';
-import 'client-shared.dart';
-
-main() {
-  setup();
-
-  // Request the navigation data so we can build the HTML for it.
-  HttpRequest.getString('${prefix}nav.json').then((text) {
-    var json = JSON.decode(text);
-    buildNavigation(json);
-    setupSearch(json);
-  });
-}
-
-
-/**
- * Takes [libraries], a JSON array representing a set of libraries and builds
- * the appropriate navigation DOM for it relative to the current library and
- * type.
- */
-buildNavigation(List libraries) {
-  final html = new StringBuffer();
-  for (Map libraryInfo in libraries) {
-    String libraryName = libraryInfo[NAME];
-    html.write('<h2><div class="icon-library"></div>');
-    if (currentLibrary == libraryName && currentType == null) {
-      html.write('<strong>${md.escapeHtml(libraryName)}</strong>');
-    } else {
-      final url = getLibraryUrl(libraryName);
-      html.write('<a href="$url">${md.escapeHtml(libraryName)}</a>');
-    }
-    html.write('</h2>');
-
-    // Only list the types for the current library.
-    if (currentLibrary == libraryName && libraryInfo.containsKey(TYPES)) {
-      buildLibraryNavigation(html, libraryInfo);
-    }
-  }
-
-  // Insert it into the DOM.
-  final navElement = document.query('.nav');
-  navElement.innerHtml = html.toString();
-}
-
-/** Writes the navigation for the types contained by [library] to [html]. */
-buildLibraryNavigation(StringBuffer html, Map libraryInfo) {
-  // Show the exception types separately.
-  final types = [];
-  final exceptions = [];
-
-  for (Map typeInfo in libraryInfo[TYPES]) {
-    var name = typeInfo[NAME];
-    if (name.endsWith('Exception') || name.endsWith('Error')) {
-      exceptions.add(typeInfo);
-    } else {
-      types.add(typeInfo);
-    }
-  }
-
-  if (types.length == 0 && exceptions.length == 0) return;
-
-  writeType(String icon, Map typeInfo) {
-    html.write('<li>');
-    if (currentType == typeInfo[NAME]) {
-      html.write(
-          '<div class="icon-$icon"></div><strong>${getTypeName(typeInfo)}</strong>');
-    } else {
-      html.write(
-          '''
-          <a href="${getTypeUrl(currentLibrary, typeInfo)}">
-            <div class="icon-$icon"></div>${getTypeName(typeInfo)}
-          </a>
-          ''');
-    }
-    html.write('</li>');
-  }
-
-  html.write('<ul class="icon">');
-  types.forEach((typeInfo) =>
-      writeType(kindToString(typeInfo[KIND]), typeInfo));
-  exceptions.forEach((typeInfo) => writeType('exception', typeInfo));
-  html.write('</ul>');
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
deleted file mode 100644
index d6e8daa..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
+++ /dev/null
@@ -1,114 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library client_shared;
-
-import 'dart:html';
-import 'dropdown.dart';
-import '../../classify.dart';
-import '../dartdoc/nav.dart';
-
-
-// Code shared between the different client-side libraries.
-
-// The names of the library and type that this page documents.
-String currentLibrary = null;
-String currentType = null;
-
-// What we need to prefix relative URLs with to get them to work.
-String prefix = '';
-
-void setup() {
-  setupLocation();
-  setupShortcuts();
-  enableCodeBlocks();
-  enableShowHideInherited();
-}
-
-void setupLocation() {
-  // Figure out where we are.
-  final body = document.query('body');
-  currentLibrary = body.dataset['library'];
-  currentType = body.dataset['type'];
-  prefix = (currentType != null) ? '../' : '';
-}
-
-/**
- * Finds all code blocks and makes them toggleable. Syntax highlights each
- * code block the first time it's shown.
- */
-enableCodeBlocks() {
-  for (var elem in document.queryAll('.method, .field')) {
-    var showCode = elem.query('.show-code');
-
-    // Skip it if we don't have a code link. Will happen if source code is
-    // disabled.
-    if (showCode == null) continue;
-
-    var preList = elem.queryAll('pre.source');
-
-    showCode.onClick.listen((e) {
-      for (final pre in preList) {
-        if (pre.classes.contains('expanded')) {
-          pre.classes.remove('expanded');
-        } else {
-          // Syntax highlight.
-          if (!pre.classes.contains('formatted')) {
-            pre.innerHtml = classifySource(pre.text);
-            pre.classes.add('formatted');
-          };
-          pre.classes.add('expanded');
-        }
-      }
-    });
-  }
-}
-
-/**
- * Enables show/hide functionality for inherited members and comments.
- */
-void enableShowHideInherited() {
-  var showInherited = document.query('#show-inherited');
-  if (showInherited == null) return;
-  showInherited.dataset.putIfAbsent('show-inherited', () => 'block');
-  showInherited.onClick.listen((e) {
-    String display = showInherited.dataset['show-inherited'];
-    if (display == 'block') {
-      display = 'none';
-      showInherited.innerHtml = 'Show inherited';
-    } else {
-      display = 'block';
-      showInherited.innerHtml = 'Hide inherited';
-    }
-    showInherited.dataset['show-inherited'] = display;
-    for (var elem in document.queryAll('.inherited')) {
-      elem.style.display = display;
-    }
-  });
-
-}
-
-/** Turns [name] into something that's safe to use as a file name. */
-String sanitize(String name) => name.replaceAll(':', '_').replaceAll('/', '_');
-
-String getTypeName(Map typeInfo) =>
-    typeInfo.containsKey('args')
-        ? '${typeInfo[NAME]}&lt;${typeInfo[NAME]}&gt;'
-        : typeInfo[NAME];
-
-String getLibraryUrl(String libraryName) =>
-    '$prefix${sanitize(libraryName)}.html';
-
-String getTypeUrl(String libraryName, Map typeInfo) =>
-    '$prefix${sanitize(libraryName)}/${sanitize(typeInfo[NAME])}.html';
-
-String getLibraryMemberUrl(String libraryName, Map memberInfo) =>
-    '$prefix${sanitize(libraryName)}.html#${getMemberAnchor(memberInfo)}';
-
-String getTypeMemberUrl(String libraryName, String typeName, Map memberInfo) =>
-    '$prefix${sanitize(libraryName)}/${sanitize(typeName)}.html#'
-    '${getMemberAnchor(memberInfo)}';
-
-String getMemberAnchor(Map memberInfo) => memberInfo.containsKey(LINK_NAME)
-    ? memberInfo[LINK_NAME] : memberInfo[NAME];
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart b/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
deleted file mode 100644
index 8101f5d..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
+++ /dev/null
@@ -1,363 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library dropdown;
-
-import 'dart:html';
-import 'search.dart';
-import 'client-shared.dart';
-import '../dartdoc/nav.dart';
-
-List libraryList;
-InputElement searchInput;
-DivElement dropdown;
-
-/**
- * Update the search drop down based on the current search text.
- */
-updateDropDown(Event event) {
-  if (libraryList == null) return;
-  if (searchInput == null) return;
-  if (dropdown == null) return;
-
-  var results = <Result>[];
-  String text = searchInput.value;
-  if (text == currentSearchText) {
-    return;
-  }
-  if (text.isEmpty) {
-    updateResults(text, results);
-    hideDropDown();
-    return;
-  }
-  if (text.contains('.')) {
-    // Search type members.
-    String typeText = text.substring(0, text.indexOf('.'));
-    String memberText = text.substring(text.indexOf('.') + 1);
-
-    if (typeText.isEmpty && memberText.isEmpty) {
-      // Don't search on '.'.
-    } else if (typeText.isEmpty) {
-      // Search text is of the form '.id' => Look up members.
-      matchAllMembers(results, memberText);
-    } else if (memberText.isEmpty) {
-      // Search text is of the form 'Type.' => Look up members in 'Type'.
-      matchAllMembersInType(results, typeText, memberText);
-    } else {
-      // Search text is of the form 'Type.id' => Look up member 'id' in 'Type'.
-      matchMembersInType(results, text, typeText, memberText);
-    }
-  } else {
-    // Search all entities.
-    var searchText = new SearchText(text);
-    for (Map<String,dynamic> library in libraryList)  {
-      matchLibrary(results, searchText, library);
-      matchLibraryMembers(results, searchText, library);
-      matchTypes(results, searchText, library);
-    }
-  }
-  var elements = <Element>[];
-  var table = new TableElement();
-  table.classes.add('drop-down-table');
-  elements.add(table);
-
-  if (results.isEmpty) {
-    var row = table.insertRow(0);
-    row.innerHtml = "<tr><td>No matches found for '$text'.</td></tr>";
-  } else {
-    results.sort(resultComparator);
-
-    var count = 0;
-    for (Result result in results) {
-      result.addRow(table);
-      if (++count >= 10) {
-        break;
-      }
-    }
-    if (results.length >= 10) {
-      var row = table.insertRow(table.rows.length);
-      row.innerHtml = '<tr><td>+ ${results.length-10} more.</td></tr>';
-      results = results.sublist(0, 10);
-    }
-  }
-  dropdown.children = elements;
-  updateResults(text, results);
-  showDropDown();
-}
-
-void matchAllMembers(List<Result> results, String memberText) {
-  var searchText = new SearchText(memberText);
-  for (Map<String,dynamic> library in libraryList)  {
-    String libraryName = library[NAME];
-    if (library.containsKey(TYPES)) {
-      for (Map<String,dynamic> type in library[TYPES]) {
-        String typeName = type[NAME];
-        if (type.containsKey(MEMBERS)) {
-          for (Map<String,dynamic> member in type[MEMBERS]) {
-            StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
-            if (memberMatch != null) {
-              results.add(new Result(memberMatch, member[KIND],
-                  getTypeMemberUrl(libraryName, typeName, member),
-                  library: libraryName, type: typeName, args: type[ARGS],
-                  noargs: member[NO_PARAMS]));
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-void matchAllMembersInType(List<Result> results,
-                           String typeText, String memberText) {
-  var searchText = new SearchText(typeText);
-  var emptyText = new SearchText(memberText);
-  for (Map<String,dynamic> library in libraryList)  {
-    String libraryName = library[NAME];
-    if (library.containsKey(TYPES)) {
-      for (Map<String,dynamic> type in library[TYPES]) {
-        String typeName = type[NAME];
-        StringMatch typeMatch = obtainMatch(searchText, typeName);
-        if (typeMatch != null) {
-          if (type.containsKey(MEMBERS)) {
-            for (Map<String,dynamic> member in type[MEMBERS]) {
-              StringMatch memberMatch = obtainMatch(emptyText,
-                  member[NAME]);
-              results.add(new Result(memberMatch, member[KIND],
-                  getTypeMemberUrl(libraryName, typeName, member),
-                  library: libraryName, prefix: typeMatch,
-                  noargs: member[NO_PARAMS]));
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-void matchMembersInType(List<Result> results,
-                        String text, String typeText, String memberText) {
-  var searchText = new SearchText(text);
-  var typeSearchText = new SearchText(typeText);
-  var memberSearchText = new SearchText(memberText);
-  for (Map<String,dynamic> library in libraryList)  {
-    String libraryName = library[NAME];
-    if (library.containsKey(TYPES)) {
-      for (Map<String,dynamic> type in library[TYPES]) {
-        String typeName = type[NAME];
-        StringMatch typeMatch = obtainMatch(typeSearchText, typeName);
-        if (typeMatch != null) {
-          if (type.containsKey(MEMBERS)) {
-            for (Map<String,dynamic> member in type[MEMBERS]) {
-              // Check for constructor match.
-              StringMatch constructorMatch = obtainMatch(searchText,
-                  member[NAME]);
-              if (constructorMatch != null) {
-                results.add(new Result(constructorMatch, member[KIND],
-                    getTypeMemberUrl(libraryName, typeName, member),
-                    library: libraryName, noargs: member[NO_PARAMS]));
-              } else {
-                // Try member match.
-                StringMatch memberMatch = obtainMatch(memberSearchText,
-                    member[NAME]);
-                if (memberMatch != null) {
-                  results.add(new Result(memberMatch, member[KIND],
-                      getTypeMemberUrl(libraryName, typeName, member),
-                      library: libraryName, prefix: typeMatch,
-                      args: type[ARGS], noargs: member[NO_PARAMS]));
-                }
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-void matchLibrary(List<Result> results, SearchText searchText, Map library) {
-  String libraryName = library[NAME];
-  StringMatch libraryMatch = obtainMatch(searchText, libraryName);
-  if (libraryMatch != null) {
-    results.add(new Result(libraryMatch, LIBRARY,
-                           getLibraryUrl(libraryName)));
-  }
-}
-
-void matchLibraryMembers(List<Result> results, SearchText searchText,
-                          Map library) {
-  if (library.containsKey(MEMBERS)) {
-    String libraryName = library[NAME];
-    for (Map<String,dynamic> member in library[MEMBERS]) {
-      StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
-      if (memberMatch != null) {
-        results.add(new Result(memberMatch, member[KIND],
-                               getLibraryMemberUrl(libraryName, member),
-                               library: libraryName, noargs: member[NO_PARAMS]));
-      }
-    }
-  }
-}
-
-void matchTypes(List<Result> results, SearchText searchText,
-                Map library) {
-  if (library.containsKey(TYPES)) {
-    String libraryName = library[NAME];
-    for (Map<String,dynamic> type in library[TYPES]) {
-      String typeName = type[NAME];
-      matchType(results, searchText, libraryName, type);
-      matchTypeMembers(results, searchText, libraryName, type);
-    }
-  }
-}
-
-void matchType(List<Result> results, SearchText searchText,
-               String libraryName, Map type) {
-  String typeName = type[NAME];
-  StringMatch typeMatch = obtainMatch(searchText, typeName);
-  if (typeMatch != null) {
-    results.add(new Result(typeMatch, type[KIND],
-                           getTypeUrl(libraryName, type),
-                           library: libraryName, args: type[ARGS]));
-  }
-}
-
-void matchTypeMembers(List<Result> results, SearchText searchText,
-                      String libraryName, Map type) {
-  if (type.containsKey(MEMBERS)) {
-    String typeName = type[NAME];
-    for (Map<String,dynamic> member in type[MEMBERS]) {
-      StringMatch memberMatch = obtainMatch(searchText, member[NAME]);
-      if (memberMatch != null) {
-        results.add(new Result(memberMatch, member[KIND],
-            getTypeMemberUrl(libraryName, typeName, member),
-            library: libraryName, type: typeName, args: type[ARGS],
-            noargs: member[NO_PARAMS]));
-      }
-    }
-  }
-}
-
-String currentSearchText;
-Result _currentResult;
-List<Result> currentResults = const <Result>[];
-
-void updateResults(String searchText, List<Result> results) {
-  currentSearchText = searchText;
-  currentResults = results;
-  if (currentResults.isEmpty) {
-    _currentResultIndex = -1;
-    currentResult = null;
-  } else {
-    _currentResultIndex = 0;
-    currentResult = currentResults[0];
-  }
-}
-
-int _currentResultIndex;
-
-void set currentResultIndex(int index) {
-  if (index < -1) {
-    return;
-  }
-  if (index >= currentResults.length) {
-    return;
-  }
-  if (index != _currentResultIndex) {
-    _currentResultIndex = index;
-    if (index >= 0) {
-      currentResult = currentResults[_currentResultIndex];
-    } else {
-      currentResult = null;
-    }
-  }
-}
-
-int get currentResultIndex => _currentResultIndex;
-
-void set currentResult(Result result) {
-  if (_currentResult != result) {
-    if (_currentResult != null) {
-      _currentResult.row.classes.remove('drop-down-link-select');
-    }
-    _currentResult = result;
-    if (_currentResult != null) {
-      _currentResult.row.classes.add('drop-down-link-select');
-    }
-  }
-}
-
-Result get currentResult => _currentResult;
-
-/**
- * Navigate the search drop down using up/down inside the search field. Follow
- * the result link on enter.
- */
-void handleUpDown(KeyboardEvent event) {
-  if (event.keyCode == KeyCode.UP) {
-    currentResultIndex--;
-    event.preventDefault();
-  } else if (event.keyCode == KeyCode.DOWN) {
-    currentResultIndex++;
-    event.preventDefault();
-  } else if (event.keyCode == KeyCode.ENTER) {
-    if (currentResult != null) {
-      window.location.href = currentResult.url;
-      event.preventDefault();
-      hideDropDown();
-    }
-  }
-}
-
-/** Show the search drop down unless there are no current results. */
-void showDropDown() {
-  if (currentResults.isEmpty) {
-    hideDropDown();
-  } else {
-    dropdown.style.visibility = 'visible';
-  }
-}
-
-/** Used to prevent hiding the drop down when it is clicked. */
-bool hideDropDownSuspend = false;
-
-/** Hide the search drop down unless suspended. */
-void hideDropDown() {
-  if (hideDropDownSuspend) return;
-
-  dropdown.style.visibility = 'hidden';
-}
-
-/** Activate search on Ctrl+3 and S. */
-void shortcutHandler(KeyboardEvent event) {
-  if (event.keyCode == KeyCode.THREE && event.ctrlKey) {
-    searchInput.focus();
-    event.preventDefault();
-  } else if (event.target != searchInput && event.keyCode == KeyCode.S) {
-    // Allow writing 's' in the search input.
-    searchInput.focus();
-    event.preventDefault();
-  }
-}
-
-/**
- * Setup window shortcuts.
- */
-void setupShortcuts() {
-  window.onKeyDown.listen(shortcutHandler);
-}
-
-/** Setup search hooks. */
-void setupSearch(var libraries) {
-  libraryList = libraries;
-  searchInput = query('#q');
-  dropdown = query('#drop-down');
-
-  searchInput.onKeyDown.listen(handleUpDown);
-  searchInput.onKeyUp.listen(updateDropDown);
-  searchInput.onChange.listen(updateDropDown);
-  searchInput.onReset.listen(updateDropDown);
-  searchInput.onFocus.listen((event) => showDropDown());
-  searchInput.onBlur.listen((event) => hideDropDown());
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/search.dart b/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
deleted file mode 100644
index ee5f922..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
+++ /dev/null
@@ -1,230 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library search;
-
-import 'dart:html';
-import 'dropdown.dart';
-import '../dartdoc/nav.dart';
-
-/**
- * [SearchText] represent the search field text. The text is viewed in three
- * ways: [text] holds the original search text, used for performing
- * case-sensitive matches, [lowerCase] holds the lower-case search text, used
- * for performing case-insenstive matches, [camelCase] holds a camel-case
- * interpretation of the search text, used to order matches in camel-case.
- */
-class SearchText {
-  final String text;
-  final String lowerCase;
-  final String camelCase;
-
-  SearchText(String searchText)
-      : text = searchText,
-        lowerCase = searchText.toLowerCase(),
-        camelCase = searchText.isEmpty ? ''
-            : '${searchText.substring(0, 1).toUpperCase()}'
-              '${searchText.substring(1)}';
-
-  int get length => text.length;
-
-  bool get isEmpty => length == 0;
-}
-
-/**
- * [StringMatch] represents the case-insensitive matching of [searchText] as a
- * substring within a [text].
- */
-class StringMatch {
-  final SearchText searchText;
-  final String text;
-  final int matchOffset;
-  final int matchEnd;
-
-  StringMatch(this.searchText,
-              this.text, this.matchOffset, this.matchEnd);
-
-  /**
-   * Returns the HTML representation of the match.
-   */
-  String toHtml() {
-    return '${text.substring(0, matchOffset)}'
-           '<span class="drop-down-link-highlight">$matchText</span>'
-           '${text.substring(matchEnd)}';
-  }
-
-  String get matchText =>
-      text.substring(matchOffset, matchEnd);
-
-  /**
-   * Is [:true:] iff [searchText] matches the full [text] case-sensitively.
-   */
-  bool get isFullMatch => text == searchText.text;
-
-  /**
-   * Is [:true:] iff [searchText] matches a substring of [text]
-   * case-sensitively.
-   */
-  bool get isExactMatch => matchText == searchText.text;
-
-  /**
-   * Is [:true:] iff [searchText] matches a substring of [text] when
-   * [searchText] is interpreted as camel case.
-   */
-  bool get isCamelCaseMatch => matchText == searchText.camelCase;
-}
-
-/**
- * [Result] represents a match of the search text on a library, type or member.
- */
-class Result {
-  final StringMatch prefix;
-  final StringMatch match;
-
-  final String library;
-  final String type;
-  final String args;
-  final String kind;
-  final String url;
-  final bool noargs;
-
-  TableRowElement row;
-
-  Result(this.match, this.kind, this.url,
-         {this.library: null, this.type: null, String args: null,
-          this.prefix: null, this.noargs: false})
-      : this.args = args != null ? '&lt;$args&gt;' : '';
-
-  bool get isTopLevel => prefix == null && type == null;
-
-  void addRow(TableElement table) {
-    if (row != null) return;
-
-    clickHandler(Event event) {
-      window.location.href = url;
-      hideDropDown();
-    }
-
-    row = table.insertRow(table.rows.length);
-    row.classes.add('drop-down-link-tr');
-    row.onMouseDown.listen((event) => hideDropDownSuspend = true);
-    row.onClick.listen(clickHandler);
-    row.onMouseUp.listen((event) => hideDropDownSuspend = false);
-    var sb = new StringBuffer();
-    sb.write('<td class="drop-down-link-td">');
-    sb.write('<table class="drop-down-table"><tr><td colspan="2">');
-    if (kind == GETTER) {
-      sb.write('get ');
-    } else if (kind == SETTER) {
-      sb.write('set ');
-    }
-    sb.write(match.toHtml());
-    if (kind == CLASS || kind == TYPEDEF) {
-      sb.write(args);
-    } else if (kind == CONSTRUCTOR || kind == METHOD) {
-      if (noargs) {
-        sb.write("()");
-      } else {
-        sb.write('(...)');
-      }
-    }
-    sb.write('</td></tr><tr><td class="drop-down-link-kind">');
-    sb.write(kindToString(kind));
-    if (prefix != null) {
-      sb.write(' in ');
-      sb.write(prefix.toHtml());
-      sb.write(args);
-    } else if (type != null) {
-      sb.write(' in ');
-      sb.write(type);
-      sb.write(args);
-    }
-
-    sb.write('</td><td class="drop-down-link-library">');
-    if (library != null) {
-      sb.write('library $library');
-    }
-    sb.write('</td></tr></table></td>');
-    row.innerHtml = sb.toString();
-  }
-}
-
-/**
- * Creates a [StringMatch] object for [text] if a substring matches
- * [searchText], or returns [: null :] if no match is found.
- */
-StringMatch obtainMatch(SearchText searchText, String text) {
-  if (searchText.isEmpty) {
-    return new StringMatch(searchText, text, 0, 0);
-  }
-  int offset = text.toLowerCase().indexOf(searchText.lowerCase);
-  if (offset != -1) {
-    return new StringMatch(searchText, text,
-                           offset, offset + searchText.length);
-  }
-  return null;
-}
-
-/**
- * Compares [a] and [b], regarding [:true:] smaller than [:false:].
- *
- * [:null:]-values are not handled.
- */
-int compareBools(bool a, bool b) {
-  if (a == b) return 0;
-  return a ? -1 : 1;
-}
-
-/**
- * Used to sort the search results heuristically to show the more relevant match
- * in the top of the dropdown.
- */
-int resultComparator(Result a, Result b) {
-  // Favor top level entities.
-  int result = compareBools(a.isTopLevel, b.isTopLevel);
-  if (result != 0) return result;
-
-  if (a.prefix != null && b.prefix != null) {
-    // Favor full prefix matches.
-    result = compareBools(a.prefix.isFullMatch, b.prefix.isFullMatch);
-    if (result != 0) return result;
-  }
-
-  // Favor matches in the start.
-  result = compareBools(a.match.matchOffset == 0,
-                        b.match.matchOffset == 0);
-  if (result != 0) return result;
-
-  // Favor matches to the end. For example, prefer 'cancel' over 'cancelable'
-  result = compareBools(a.match.matchEnd == a.match.text.length,
-                        b.match.matchEnd == b.match.text.length);
-  if (result != 0) return result;
-
-  // Favor exact case-sensitive matches.
-  result = compareBools(a.match.isExactMatch, b.match.isExactMatch);
-  if (result != 0) return result;
-
-  // Favor matches that do not break camel-case.
-  result = compareBools(a.match.isCamelCaseMatch, b.match.isCamelCaseMatch);
-  if (result != 0) return result;
-
-  // Favor matches close to the begining.
-  result = a.match.matchOffset.compareTo(b.match.matchOffset);
-  if (result != 0) return result;
-
-  if (a.type != null && b.type != null) {
-    // Favor short type names over long.
-    result = a.type.length.compareTo(b.type.length);
-    if (result != 0) return result;
-
-    // Sort type alphabetically.
-    // TODO(4805): Use [:type.compareToIgnoreCase] when supported.
-    result = a.type.toLowerCase().compareTo(b.type.toLowerCase());
-    if (result != 0) return result;
-  }
-
-  // Sort match alphabetically.
-  // TODO(4805): Use [:text.compareToIgnoreCase] when supported.
-  return a.match.text.toLowerCase().compareTo(b.match.text.toLowerCase());
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart b/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart
deleted file mode 100644
index 7ee8828..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library dart2js_util;
-
-import 'dart:async' show Future;
-import 'dart:io' show Path;
-
-import '../../../compiler/compiler.dart' as api;
-import '../../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js
-    show analyze, Dart2JsMirrorSystem;
-import '../../../compiler/implementation/mirrors/mirrors.dart'
-    show MirrorSystem;
-import '../../../compiler/implementation/source_file_provider.dart'
-    show FormattingDiagnosticHandler, SourceFileProvider,
-         CompilerSourceFileProvider;
-import '../../../compiler/implementation/filenames.dart'
-    show appendSlash, currentDirectory;
-
-// TODO(johnniwinther): Support client configurable providers.
-
-/**
- * Returns a future that completes to a non-null String when [script]
- * has been successfully compiled.
- */
-// TODO(amouravski): Remove this method and call dart2js via a process instead.
-Future<String> compile(String script,
-                       String libraryRoot,
-                       {String packageRoot,
-                        List<String> options: const <String>[],
-                        api.DiagnosticHandler diagnosticHandler}) {
-  SourceFileProvider provider = new CompilerSourceFileProvider();
-  if (diagnosticHandler == null) {
-    diagnosticHandler =
-        new FormattingDiagnosticHandler(provider).diagnosticHandler;
-  }
-  Uri scriptUri = currentDirectory.resolve(script.toString());
-  Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot'));
-  Uri packageUri = null;
-  if (packageRoot != null) {
-    packageUri = currentDirectory.resolve(appendSlash('$packageRoot'));
-  }
-  return api.compile(scriptUri, libraryUri, packageUri,
-      provider.readStringFromUri, diagnosticHandler, options);
-}
-
-/**
- * Analyzes set of libraries and provides a mirror system which can be used for
- * static inspection of the source code.
- */
-Future<MirrorSystem> analyze(List<String> libraries,
-                             String libraryRoot,
-                             {String packageRoot,
-                              List<String> options: const <String>[],
-                              api.DiagnosticHandler diagnosticHandler}) {
-  SourceFileProvider provider = new CompilerSourceFileProvider();
-  if (diagnosticHandler == null) {
-    diagnosticHandler =
-        new FormattingDiagnosticHandler(provider).diagnosticHandler;
-  }
-  Uri libraryUri = currentDirectory.resolve(appendSlash('$libraryRoot'));
-  Uri packageUri = null;
-  if (packageRoot != null) {
-    packageUri = currentDirectory.resolve(appendSlash('$packageRoot'));
-  }
-  List<Uri> librariesUri = <Uri>[];
-  for (String library in libraries) {
-    librariesUri.add(currentDirectory.resolve(library));
-  }
-  return dart2js.analyze(librariesUri, libraryUri, packageUri,
-                         provider.readStringFromUri, diagnosticHandler,
-                         options);
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/nav.dart b/sdk/lib/_internal/dartdoc/lib/src/dartdoc/nav.dart
deleted file mode 100644
index 3948f8e..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/nav.dart
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library dartdoc_nav;
-
-/*
- * Constant values used for encoding navigation info.
- *
- * The generated JSON data is a list of LibraryInfo maps, defined as follows:
- *
- *     LibraryInfo = {
- *         String NAME, // Library name.
- *         List<TypeInfo> TYPES, // Library types.
- *         List<MemberInfo> MEMBERS, // Library functions and variables.
- *     };
- *     TypeInfo = {
- *         String NAME, // Type name.
- *         String ARGS, // Type variables, e.g. "<K,V>". Optional.
- *         String KIND, // One of CLASS or TYPEDEF.
- *         List<MemberInfo> MEMBERS, // Type fields and methods.
- *     };
- *     MemberInfo = {
- *        String NAME, // Member name.
- *        String KIND, // One of FIELD, CONSTRUCTOR, METHOD, GETTER, or SETTER.
- *        String LINK_NAME, // Anchor name for the member if different from
- *                          // NAME.
- *        bool NO_PARAMS, // Is true if member takes no arguments?
- *     };
- *
- *
- * TODO(johnniwinther): Shorten the string values to reduce JSON output size.
- */
-
-const String LIBRARY = 'library';
-const String CLASS = 'class';
-const String TYPEDEF = 'typedef';
-const String MEMBERS = 'members';
-const String TYPES = 'types';
-const String ARGS = 'args';
-const String NAME = 'name';
-const String KIND = 'kind';
-const String FIELD = 'field';
-const String CONSTRUCTOR = 'constructor';
-const String METHOD = 'method';
-const String NO_PARAMS = 'noparams';
-const String GETTER = 'getter';
-const String SETTER = 'setter';
-const String LINK_NAME = 'link_name';
-
-/**
- * Translation of const values to strings. Used to facilitate shortening of
- * constant value strings.
- */
-String kindToString(String kind) {
-  if (kind == LIBRARY) {
-    return 'library';
-  } else if (kind == CLASS) {
-    return 'class';
-  } else if (kind == TYPEDEF) {
-    return 'typedef';
-  } else if (kind == FIELD) {
-    return 'field';
-  } else if (kind == CONSTRUCTOR) {
-    return 'constructor';
-  } else if (kind == METHOD) {
-    return 'method';
-  } else if (kind == GETTER) {
-    return 'getter';
-  } else if (kind == SETTER) {
-    return 'setter';
-  }
-  return '';
-}
\ No newline at end of file
diff --git a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart b/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart
deleted file mode 100644
index 3f876b6..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/dartdoc/utils.dart
+++ /dev/null
@@ -1,142 +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.
-
-// Generic utility functions.
-library utils;
-
-import 'dart:io';
-import 'dart:math' as math;
-
-import 'package:path/path.dart' as pathos;
-
-import '../../../../compiler/implementation/mirrors/mirrors.dart';
-
-import '../export_map.dart';
-
-/** Turns [name] into something that's safe to use as a file name. */
-String sanitize(String name) => name.replaceAll(':', '_').replaceAll('/', '_');
-
-/** Returns the number of times [search] occurs in [text]. */
-int countOccurrences(String text, String search) {
-  int start = 0;
-  int count = 0;
-
-  while (true) {
-    start = text.indexOf(search, start);
-    if (start == -1) break;
-    count++;
-    // Offsetting by search length means overlapping results are not counted.
-    start += search.length;
-  }
-
-  return count;
-}
-
-/** Repeats [text] [count] times, separated by [separator] if given. */
-String repeat(String text, int count, {String separator}) {
-  // TODO(rnystrom): Should be in corelib.
-  final buffer = new StringBuffer();
-  for (int i = 0; i < count; i++) {
-    buffer.write(text);
-    if ((i < count - 1) && (separator != null)) buffer.write(separator);
-  }
-
-  return buffer.toString();
-}
-
-/** Removes up to [indentation] leading whitespace characters from [text]. */
-String unindent(String text, int indentation) {
-  var start;
-  for (start = 0; start < math.min(indentation, text.length); start++) {
-    // Stop if we hit a non-whitespace character.
-    if (text[start] != ' ') break;
-  }
-
-  return text.substring(start);
-}
-
-/** Sorts the map by the key, doing a case-insensitive comparison. */
-List<Mirror> orderByName(Iterable<Mirror> list) {
-  final elements = new List<Mirror>.from(list);
-  elements.sort((a,b) {
-    String aName = a.simpleName.toLowerCase();
-    String bName = b.simpleName.toLowerCase();
-    bool doma = aName.startsWith(r"$dom");
-    bool domb = bName.startsWith(r"$dom");
-    return doma == domb ? aName.compareTo(bName) : doma ? 1 : -1;
-  });
-  return elements;
-}
-
-/**
- * Joins [items] into a single, comma-separated string using [conjunction].
- * E.g. `['A', 'B', 'C']` becomes `"A, B, and C"`.
- */
-String joinWithCommas(List<String> items, [String conjunction = 'and']) {
-  if (items.length == 1) return items[0];
-  if (items.length == 2) return "${items[0]} $conjunction ${items[1]}";
-  return '${items.take(items.length - 1).join(', ')}'
-    ', $conjunction ${items[items.length - 1]}';
-}
-
-void writeString(File file, String text) {
-  var randomAccessFile = file.openSync(mode: FileMode.WRITE);
-  randomAccessFile.writeStringSync(text);
-  randomAccessFile.closeSync();
-}
-
-/**
- * Converts [uri], which should come from a Dart import or export, to a local
- * filesystem path. [basePath] is the base directory to use when converting
- * relative URIs; without it, relative URIs will not be converted. [packageRoot]
- * is the `packages` directory to use when converting `package:` URIs; without
- * it, `package:` URIs will not be converted.
- *
- * If a URI cannot be converted, this will return `null`.
- */
-String importUriToPath(Uri uri, {String basePath, String packageRoot}) {
-  if (uri.scheme == 'file') return pathos.fromUri(uri);
-
-  if (basePath != null && uri.scheme == '') {
-    return pathos.normalize(pathos.absolute(pathos.join(basePath, uri.path)));
-  }
-
-  if (packageRoot != null && uri.scheme == 'package') {
-    return pathos.normalize(pathos.absolute(
-        pathos.join(packageRoot, uri.path)));
-  }
-
-  // Ignore unsupported schemes.
-  return null;
-}
-
-/**
- * If [map] contains an [Export] under [key], this merges that with [export].
- * Otherwise, it sets [key] to [export].
- */
-void addOrMergeExport(Map<LibraryMirror, Export> map,
-                      LibraryMirror key, Export export) {
-  if (map.containsKey(key)) {
-    map[key] = map[key].merge(export);
-  } else {
-    map[key] = export;
-  }
-}
-
-/// A pair of values.
-class Pair<E, F> {
-  E first;
-  F last;
-
-  Pair(this.first, this.last);
-
-  String toString() => '($first, $last)';
-
-  bool operator==(other) {
-    if (other is! Pair) return false;
-    return other.first == first && other.last == last;
-  }
-
-  int get hashCode => first.hashCode ^ last.hashCode;
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/export_map.dart b/sdk/lib/_internal/dartdoc/lib/src/export_map.dart
deleted file mode 100644
index 09f894c..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/export_map.dart
+++ /dev/null
@@ -1,233 +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.
-
-/// This library uses the Dart analyzer to find the exports for a set of
-/// libraries. It stores these exports in an [ExportMap]. This is used to
-/// display exported members as part of the exporting library, since dart2js
-/// doesn't provide this information itself.
-library export_map;
-
-import '../../../compiler/implementation/mirrors/mirrors.dart';
-import '../../../compiler/implementation/mirrors/mirrors_util.dart';
-
-/// A class that tracks which libraries export which other libraries.
-class ExportMap {
-  /// A map from libraries to their [Export]s.
-  ///
-  /// Each key is a library and each value is a list of [Export]s for that
-  /// library. There's guaranteed to be only one [Export] of a given library
-  /// in a given list.
-  final Map<LibraryMirror, List<Export>> exports = {};
-
-  /// A cache of the transitive exports for each library. The values are maps
-  /// from the exported libraries to the [Export] objects, to make it easier to
-  /// merge multiple exports of the same library.
-  Map<LibraryMirror, Map<LibraryMirror, Export>> _transitiveExports = {};
-
-  ExportMap(MirrorSystem mirrors) {
-    mirrors.libraries.values.where((lib) => !_isDartLibrary(lib))
-                            .forEach(_computeExports);
-  }
-
-  bool _isDartLibrary(LibraryMirror lib) => lib.uri.scheme == 'dart';
-
-  /// Compute all non-dart: exports in [library].
-  void _computeExports(LibraryMirror library) {
-    var exportMap = {};
-    library.libraryDependencies
-        .where((mirror) =>
-            mirror.isExport && !_isDartLibrary(mirror.targetLibrary))
-        .map((mirror) => new Export.fromMirror(mirror))
-        .forEach((export) {
-      var target = export.exported;
-      if (exportMap.containsKey(target)) {
-        exportMap[target] = exportMap[target].merge(export);
-      } else {
-        exportMap[target] = export;
-      }
-    });
-    exports[library] = exportMap.values.toList();
-  }
-
-  /// Returns a list of all exports that [library] transitively exports. This
-  /// means that if [library] exports another library that in turn exports a
-  /// third, the third library will be included in the returned list.
-  ///
-  /// This will automatically handle nested `hide` and `show` directives on the
-  /// exports, as well as merging multiple exports of the same library.
-  List<Export> transitiveExports(LibraryMirror library) {
-    Map<LibraryMirror, Export> _getTransitiveExports(LibraryMirror library) {
-      if (_transitiveExports.containsKey(library)) {
-        return _transitiveExports[library];
-      }
-
-      var exportsByPath = <LibraryMirror, Export>{};
-      _transitiveExports[library] = exportsByPath;
-      if (exports[library] == null) return exportsByPath;
-
-      for (var export in exports[library]) {
-        exportsByPath[export.exported] = export;
-      }
-
-      for (var export in exports[library]) {
-        for (var subExport in _getTransitiveExports(export.exported).values) {
-          subExport = export.compose(subExport);
-          if (exportsByPath.containsKey(subExport.exported)) {
-            subExport = subExport.merge(exportsByPath[subExport.exported]);
-          }
-          exportsByPath[subExport.exported] = subExport;
-        }
-      }
-      return exportsByPath;
-    }
-
-    return _getTransitiveExports(library).values.toList();
-  }
-}
-
-/// A class that represents one library exporting another.
-class Export {
-  /// The library that contains this export.
-  final LibraryMirror exporter;
-
-  /// The library being exported.
-  final LibraryMirror exported;
-
-  /// The set of identifiers that are explicitly being exported. If this is
-  /// non-empty, no identifiers other than these will be visible.
-  ///
-  /// One or both of [show] and [hide] will always be empty.
-  Set<String> get show => _show;
-  Set<String> _show;
-
-  /// The set of identifiers that are not exported.
-  ///
-  /// One or both of [show] and [hide] will always be empty.
-  Set<String> get hide => _hide;
-  Set<String> _hide;
-
-  /// Whether or not members exported are hidden by default.
-  bool get _hideByDefault => !show.isEmpty;
-
-  /// Creates a new export.
-  ///
-  /// This will normalize [show] and [hide] so that if both are non-empty, only
-  /// [show] will be set.
-  factory Export.fromMirror(LibraryDependencyMirror mirror) {
-    var show = <String>[];
-    var hide = <String>[];
-    for (var combinator in mirror.combinators) {
-      if (combinator.isShow) {
-        show.addAll(combinator.identifiers);
-      }
-      if (combinator.isHide) {
-        hide.addAll(combinator.identifiers);
-      }
-    }
-    return new Export(
-        mirror.sourceLibrary, mirror.targetLibrary, show: show, hide: hide);
-  }
-
-  Export(this.exporter, this.exported,
-         {Iterable<String> show, Iterable<String> hide}) {
-    _show = new Set<String>.from(show == null ? [] : show);
-    _hide = new Set<String>.from(hide == null ? [] : hide);
-
-    if (!_show.isEmpty) {
-      _show.removeAll(_hide);
-      _hide = new Set<String>();
-    }
-  }
-
-  /// Returns a new [Export] that represents [this] composed with [nested], as
-  /// though [this] was used to export a library that in turn exported [nested].
-  Export compose(Export nested) {
-    var show = new Set<String>();
-    var hide = new Set<String>();
-
-    if (this._hideByDefault) {
-      show.addAll(this.show);
-      if (nested._hideByDefault) {
-        show.retainAll(nested.show);
-      } else {
-        show.removeAll(nested.hide);
-      }
-    } else if (nested._hideByDefault) {
-      show.addAll(nested.show);
-      show.removeAll(this.hide);
-    } else {
-      hide.addAll(this.hide);
-      hide.addAll(nested.hide);
-    }
-
-    return new Export(this.exporter, nested.exported, show: show, hide: hide);
-  }
-
-  /// Returns a new [Export] that merges [this] with [nested], as though both
-  /// exports were included in the same library.
-  ///
-  /// [this] and [other] must have the same values for [exporter] and [path].
-  Export merge(Export other) {
-    if (this.exported != other.exported) {
-      throw new ArgumentError("Can't merge two Exports with different paths: "
-          "export '$exported' from '$exporter' and export '${other.exported}' "
-          "from '${other.exporter}'.");
-    } if (this.exporter != other.exporter) {
-      throw new ArgumentError("Can't merge two Exports with different "
-          "exporters: export '$exported' from '$exporter' and export "
-          "'${other.exported}' from '${other.exporter}'.");
-    }
-
-    var show = new Set<String>();
-    var hide = new Set<String>();
-
-    if (this._hideByDefault) {
-      if (other._hideByDefault) {
-        show.addAll(this.show);
-        show.addAll(other.show);
-      } else {
-        hide.addAll(other.hide);
-        hide.removeAll(this.show);
-      }
-    } else {
-      hide.addAll(this.hide);
-      if (other._hideByDefault) {
-        hide.removeAll(other.show);
-      } else {
-        hide.retainAll(other.hide);
-      }
-    }
-
-    return new Export(exporter, exported, show: show, hide: hide);
-  }
-
-  /// Returns whether or not a member named [name] is visible through this
-  /// import, as goverend by [show] and [hide].
-  bool isMemberVisible(String name) =>
-    _hideByDefault ? show.contains(name) : !hide.contains(name);
-
-  bool operator==(other) => other is Export && other.exporter == exporter &&
-      other.exported == exported && show.containsAll(other.show) &&
-      other.show.containsAll(show) && hide.containsAll(other.hide) &&
-      other.hide.containsAll(hide);
-
-  int get hashCode {
-    var hashCode = exporter.hashCode ^ exported.hashCode;
-    combineHashCode(name) => hashCode ^= name.hashCode;
-    show.forEach(combineHashCode);
-    hide.forEach(combineHashCode);
-    return hashCode;
-  }
-
-  String toString() {
-    var combinator = '';
-    if (!show.isEmpty) {
-      combinator = ' show ${show.join(', ')}';
-    } else if (!hide.isEmpty) {
-      combinator = ' hide ${hide.join(', ')}';
-    }
-    return "export '${displayName(exported)}'"
-           "$combinator (from ${displayName(exporter)})";
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart b/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart
deleted file mode 100755
index 67f4fb4..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/**
- * Simple library to serialize acyclic Dart types to JSON.
- * This library is not intended for broad consumption and should be replaced
- * with a more generic Dart serialization library when one is available.
- */
-library json_serializer;
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:mirrors';
-
-String serialize(Object o) {
-  var printer = new JsonPrinter();
-  _serialize(null, o, printer);
-  return printer.toString();
-}
-
-/// Serialize the object with pretty printing.
-String prettySerialize(Object o) {
-  var printer = new JsonPrinter(prettyPrint: true);
-  _serialize(null, o, printer);
-  return printer.toString();
-}
-
-
-void _serialize(String name, Object o, JsonPrinter printer) {
-  if (o == null) return;
-
-  if (o is List) {
-    _serializeList(name, o, printer);
-  } else if (o is Map) {
-    _serializeMap(name, o, printer);
-  } else if (o is String) {
-    printer.addString(name, o);
-  } else if (o is bool) {
-    printer.addBool(name, o);
-  } else {
-    _serializeObject(name, o, printer);
-  }
-}
-
-void _serializeObject(String name, Object o, JsonPrinter printer) {
-  printer.startObject(name);
-
-  var mirror = reflect(o);
-  var classMirror = mirror.type;
-  var members = <String>[];
-  determineAllMembers(classMirror, members);
-
-  // TODO(jacobr): this code works only because futures for mirrors return
-  // immediately.
-  for(String memberName in members) {
-    var result = mirror.getField(new Symbol(memberName));
-    _serialize(memberName, result.reflectee, printer);
-  }
-  printer.endObject();
-}
-
-void determineAllMembers(ClassMirror classMirror,
-    List<String> members) {
-  for (var mirror in classMirror.declarations.values) {
-    if (mirror is VariableMirror ||
-        (mirror is MethodMirror && mirror.isGetter)) {
-      if (!members.contains(MirrorSystem.getName(mirror.simpleName))) {
-        members.add(MirrorSystem.getName(mirror.simpleName));
-      }
-    }
-  }
-  if (classMirror.superclass != null &&
-
-      // TODO(ahe): What is this test for?  Consider removing it,
-      // dart2js will issue an error if there is a cycle in superclass
-      // hierarchy.
-      classMirror.superclass.qualifiedName != classMirror.qualifiedName &&
-
-      MirrorSystem.getName(classMirror.superclass.qualifiedName) !=
-          'dart.core.Object') {
-    determineAllMembers(classMirror.superclass, members);
-  }
-}
-
-void _serializeList(String name, List l, JsonPrinter printer) {
-  printer.startList(name);
-  for(var o in l) {
-    _serialize(null, o, printer);
-  }
-  printer.endList();
-}
-
-void _serializeMap(String name, Map m, JsonPrinter printer) {
-  printer.startObject(name);
-  m.forEach((key, value) =>
-      _serialize(key, value, printer));
-  printer.endObject();
-}
-
-class JsonPrinter {
-  static const int BACKSPACE = 8;
-  static const int TAB = 9;
-  static const int NEW_LINE = 10;
-  static const int FORM_FEED = 12;
-  static const int CARRIAGE_RETURN = 13;
-  static const int QUOTE = 34;
-  static const int BACKSLASH = 92;
-  static const int CHAR_B = 98;
-  static const int CHAR_F = 102;
-  static const int CHAR_N = 110;
-  static const int CHAR_R = 114;
-  static const int CHAR_T = 116;
-  static const int CHAR_U = 117;
-
-  StringBuffer _sb;
-  int _indent = 0;
-  bool _inSet = false;
-
-  bool prettyPrint;
-  JsonPrinter({this.prettyPrint: false}) {
-    _sb = new StringBuffer();
-  }
-
-  void startObject(String name) {
-    _start(name);
-    _sb.write('{');
-
-    _indent += 1;
-    _inSet = false;
-  }
-
-  void endObject() {
-    _indent -= 1;
-    if (_inSet) {
-      _newline();
-    }
-    _sb.write('}');
-    _inSet = true;
-  }
-
-  void startList(String name) {
-    _start(name);
-    _inSet = false;
-
-    _sb.write('[');
-    _indent += 1;
-  }
-
-  void endList() {
-    _indent -= 1;
-    if (_inSet) {
-      _newline();
-    }
-    _sb.write(']');
-    _inSet = true;
-  }
-
-  void addString(String name, String value) {
-    _start(name);
-    _sb.write('"');
-    _escape(_sb, value);
-    _sb.write('"');
-    _inSet = true;
-  }
-
-  void addBool(String name, bool value) {
-    _start(name);
-    _sb.write(value.toString());
-    _inSet = true;
-  }
-
-  void addNum(String name, num value) {
-    _start(name);
-    _sb.write(value.toString());
-    _inSet = true;
-  }
-
-  void _start(String name) {
-    if (_inSet) {
-      _sb.write(',');
-    }
-    // Do not print a newline at the beginning of the file.
-    if (!_sb.isEmpty) {
-      _newline();
-    }
-    if (name != null) {
-      _sb.write('"$name": ');
-    }
-  }
-
-  void _newline([int indent = 0]) {
-    _sb.write('\n');
-    _indent += indent;
-
-    for (var i = 0; i < _indent; ++i) {
-      _sb.write('  ');
-    }
-  }
-
-  String toString() {
-    if (prettyPrint) {
-      return _sb.toString();
-    } else {
-      // Convenient hack to remove the pretty printing this serializer adds by
-      // default.
-      return JSON.encode(JSON.decode(_sb.toString()));
-    }
-  }
-
-  static int _hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
-
-  static void _escape(StringBuffer sb, String s) {
-    final int length = s.length;
-    bool needsEscape = false;
-    final codeUnits = new List<int>();
-    for (int i = 0; i < length; i++) {
-      int codeUnit = s.codeUnitAt(i);
-      if (codeUnit < 32) {
-        needsEscape = true;
-        codeUnits.add(JsonPrinter.BACKSLASH);
-        switch (codeUnit) {
-        case JsonPrinter.BACKSPACE:
-          codeUnits.add(JsonPrinter.CHAR_B);
-          break;
-        case JsonPrinter.TAB:
-          codeUnits.add(JsonPrinter.CHAR_T);
-          break;
-        case JsonPrinter.NEW_LINE:
-          codeUnits.add(JsonPrinter.CHAR_N);
-          break;
-        case JsonPrinter.FORM_FEED:
-          codeUnits.add(JsonPrinter.CHAR_F);
-          break;
-        case JsonPrinter.CARRIAGE_RETURN:
-          codeUnits.add(JsonPrinter.CHAR_R);
-          break;
-        default:
-          codeUnits.add(JsonPrinter.CHAR_U);
-          codeUnits.add(_hexDigit((codeUnit >> 12) & 0xf));
-          codeUnits.add(_hexDigit((codeUnit >> 8) & 0xf));
-          codeUnits.add(_hexDigit((codeUnit >> 4) & 0xf));
-          codeUnits.add(_hexDigit(codeUnit & 0xf));
-          break;
-        }
-      } else if (codeUnit == JsonPrinter.QUOTE ||
-          codeUnit == JsonPrinter.BACKSLASH) {
-        needsEscape = true;
-        codeUnits.add(JsonPrinter.BACKSLASH);
-        codeUnits.add(codeUnit);
-      } else {
-        codeUnits.add(codeUnit);
-      }
-    }
-    sb.write(needsEscape ? new String.fromCharCodes(codeUnits) : s);
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/ast.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/ast.dart
deleted file mode 100644
index c966cea..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/ast.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2012, 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 markdown;
-
-/// Base class for any AST item. Roughly corresponds to Node in the DOM. Will
-/// be either an Element or Text.
-abstract class Node {
-  void accept(NodeVisitor visitor);
-}
-
-/// A named tag that can contain other nodes.
-class Element implements Node {
-  final String tag;
-  final List<Node> children;
-  final Map<String, String> attributes;
-
-  Element(this.tag, this.children)
-    : attributes = <String, String>{};
-
-  Element.empty(this.tag)
-    : children = null,
-      attributes = <String, String>{};
-
-  Element.withTag(this.tag)
-    : children = [],
-      attributes = <String, String>{};
-
-  Element.text(this.tag, String text)
-    : children = [new Text(text)],
-      attributes = <String, String>{};
-
-  bool get isEmpty => children == null;
-
-  void accept(NodeVisitor visitor) {
-    if (visitor.visitElementBefore(this)) {
-      for (final child in children) child.accept(visitor);
-      visitor.visitElementAfter(this);
-    }
-  }
-}
-
-/// A plain text element.
-class Text implements Node {
-  final String text;
-  Text(this.text);
-
-  void accept(NodeVisitor visitor) => visitor.visitText(this);
-}
-
-/// Visitor pattern for the AST. Renderers or other AST transformers should
-/// implement this.
-abstract class NodeVisitor {
-  /// Called when a Text node has been reached.
-  void visitText(Text text);
-
-  /// Called when an Element has been reached, before its children have been
-  /// visited. Return `false` to skip its children.
-  bool visitElementBefore(Element element);
-
-  /// Called when an Element has been reached, after its children have been
-  /// visited. Will not be called if [visitElementBefore] returns `false`.
-  void visitElementAfter(Element element);
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart
deleted file mode 100644
index bd14f36..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/block_parser.dart
+++ /dev/null
@@ -1,463 +0,0 @@
-// Copyright (c) 2012, 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 markdown;
-
-/// The line contains only whitespace or is empty.
-final _RE_EMPTY = new RegExp(r'^([ \t]*)$');
-
-/// A series of `=` or `-` (on the next line) define setext-style headers.
-final _RE_SETEXT = new RegExp(r'^((=+)|(-+))$');
-
-/// Leading (and trailing) `#` define atx-style headers.
-final _RE_HEADER = new RegExp(r'^(#{1,6})(.*?)#*$');
-
-/// The line starts with `>` with one optional space after.
-final _RE_BLOCKQUOTE = new RegExp(r'^[ ]{0,3}>[ ]?(.*)$');
-
-/// A line indented four spaces. Used for code blocks and lists.
-final _RE_INDENT = new RegExp(r'^(?:    |\t)(.*)$');
-
-/// Three or more hyphens, asterisks or underscores by themselves. Note that
-/// a line like `----` is valid as both HR and SETEXT. In case of a tie,
-/// SETEXT should win.
-final _RE_HR = new RegExp(r'^[ ]{0,3}((-+[ ]{0,2}){3,}|'
-                                 r'(_+[ ]{0,2}){3,}|'
-                                 r'(\*+[ ]{0,2}){3,})$');
-
-/// Really hacky way to detect block-level embedded HTML. Just looks for
-/// "<somename".
-final _RE_HTML = new RegExp(r'^<[ ]*\w+[ >]');
-
-/// A line starting with one of these markers: `-`, `*`, `+`. May have up to
-/// three leading spaces before the marker and any number of spaces or tabs
-/// after.
-final _RE_UL = new RegExp(r'^[ ]{0,3}[*+-][ \t]+(.*)$');
-
-/// A line starting with a number like `123.`. May have up to three leading
-/// spaces before the marker and any number of spaces or tabs after.
-final _RE_OL = new RegExp(r'^[ ]{0,3}\d+\.[ \t]+(.*)$');
-
-/// Maintains the internal state needed to parse a series of lines into blocks
-/// of markdown suitable for further inline parsing.
-class BlockParser {
-  final List<String> lines;
-
-  /// The markdown document this parser is parsing.
-  final Document document;
-
-  /// Index of the current line.
-  int pos;
-
-  BlockParser(this.lines, this.document)
-    : pos = 0;
-
-  /// Gets the current line.
-  String get current => lines[pos];
-
-  /// Gets the line after the current one or `null` if there is none.
-  String get next {
-    // Don't read past the end.
-    if (pos >= lines.length - 1) return null;
-    return lines[pos + 1];
-  }
-
-  void advance() {
-    pos++;
-  }
-
-  bool get isDone => pos >= lines.length;
-
-  /// Gets whether or not the current line matches the given pattern.
-  bool matches(RegExp regex) {
-    if (isDone) return false;
-    return regex.firstMatch(current) != null;
-  }
-
-  /// Gets whether or not the current line matches the given pattern.
-  bool matchesNext(RegExp regex) {
-    if (next == null) return false;
-    return regex.firstMatch(next) != null;
-  }
-}
-
-abstract class BlockSyntax {
-  /// Gets the collection of built-in block parsers. To turn a series of lines
-  /// into blocks, each of these will be tried in turn. Order matters here.
-  static List<BlockSyntax> get syntaxes {
-    // Lazy initialize.
-    if (_syntaxes == null) {
-      _syntaxes = [
-          new EmptyBlockSyntax(),
-          new BlockHtmlSyntax(),
-          new SetextHeaderSyntax(),
-          new HeaderSyntax(),
-          new CodeBlockSyntax(),
-          new BlockquoteSyntax(),
-          new HorizontalRuleSyntax(),
-          new UnorderedListSyntax(),
-          new OrderedListSyntax(),
-          new ParagraphSyntax()
-        ];
-    }
-
-    return _syntaxes;
-  }
-
-  static List<BlockSyntax> _syntaxes;
-
-  /// Gets the regex used to identify the beginning of this block, if any.
-  RegExp get pattern => null;
-
-  bool get canEndBlock => true;
-
-  bool canParse(BlockParser parser) {
-    return pattern.firstMatch(parser.current) != null;
-  }
-
-  Node parse(BlockParser parser);
-
-  List<String> parseChildLines(BlockParser parser) {
-    // Grab all of the lines that form the blockquote, stripping off the ">".
-    final childLines = <String>[];
-
-    while (!parser.isDone) {
-      final match = pattern.firstMatch(parser.current);
-      if (match == null) break;
-      childLines.add(match[1]);
-      parser.advance();
-    }
-
-    return childLines;
-  }
-
-  /// Gets whether or not [parser]'s current line should end the previous block.
-  static bool isAtBlockEnd(BlockParser parser) {
-    if (parser.isDone) return true;
-    return syntaxes.any((s) => s.canParse(parser) && s.canEndBlock);
-  }
-}
-
-class EmptyBlockSyntax extends BlockSyntax {
-  RegExp get pattern => _RE_EMPTY;
-
-  Node parse(BlockParser parser) {
-    parser.advance();
-
-    // Don't actually emit anything.
-    return null;
-  }
-}
-
-/// Parses setext-style headers.
-class SetextHeaderSyntax extends BlockSyntax {
-  bool canParse(BlockParser parser) {
-    // Note: matches *next* line, not the current one. We're looking for the
-    // underlining after this line.
-    return parser.matchesNext(_RE_SETEXT);
-  }
-
-  Node parse(BlockParser parser) {
-    final match = _RE_SETEXT.firstMatch(parser.next);
-
-    final tag = (match[1][0] == '=') ? 'h1' : 'h2';
-    final contents = parser.document.parseInline(parser.current);
-    parser.advance();
-    parser.advance();
-
-    return new Element(tag, contents);
-  }
-}
-
-/// Parses atx-style headers: `## Header ##`.
-class HeaderSyntax extends BlockSyntax {
-  RegExp get pattern => _RE_HEADER;
-
-  Node parse(BlockParser parser) {
-    final match = pattern.firstMatch(parser.current);
-    parser.advance();
-    final level = match[1].length;
-    final contents = parser.document.parseInline(match[2].trim());
-    return new Element('h$level', contents);
-  }
-}
-
-/// Parses email-style blockquotes: `> quote`.
-class BlockquoteSyntax extends BlockSyntax {
-  RegExp get pattern => _RE_BLOCKQUOTE;
-
-  Node parse(BlockParser parser) {
-    final childLines = parseChildLines(parser);
-
-    // Recursively parse the contents of the blockquote.
-    final children = parser.document.parseLines(childLines);
-
-    return new Element('blockquote', children);
-  }
-}
-
-/// Parses preformatted code blocks that are indented four spaces.
-class CodeBlockSyntax extends BlockSyntax {
-  RegExp get pattern => _RE_INDENT;
-
-  List<String> parseChildLines(BlockParser parser) {
-    final childLines = <String>[];
-
-    while (!parser.isDone) {
-      var match = pattern.firstMatch(parser.current);
-      if (match != null) {
-        childLines.add(match[1]);
-        parser.advance();
-      } else {
-        // If there's a codeblock, then a newline, then a codeblock, keep the
-        // code blocks together.
-        var nextMatch = parser.next != null ?
-            pattern.firstMatch(parser.next) : null;
-        if (parser.current.trim() == '' && nextMatch != null) {
-          childLines.add('');
-          childLines.add(nextMatch[1]);
-          parser.advance();
-          parser.advance();
-        } else {
-          break;
-        }
-      }
-    }
-    return childLines;
-  }
-
-  Node parse(BlockParser parser) {
-    final childLines = parseChildLines(parser);
-
-    // The Markdown tests expect a trailing newline.
-    childLines.add('');
-
-    // Escape the code.
-    final escaped = escapeHtml(childLines.join('\n'));
-
-    return new Element('pre', [new Element.text('code', escaped)]);
-  }
-}
-
-/// Parses horizontal rules like `---`, `_ _ _`, `*  *  *`, etc.
-class HorizontalRuleSyntax extends BlockSyntax {
-  RegExp get pattern => _RE_HR;
-
-  Node parse(BlockParser parser) {
-    final match = pattern.firstMatch(parser.current);
-    parser.advance();
-    return new Element.empty('hr');
-  }
-}
-
-/// Parses inline HTML at the block level. This differs from other markdown
-/// implementations in several ways:
-///
-/// 1.  This one is way way WAY simpler.
-/// 2.  All HTML tags at the block level will be treated as blocks. If you
-///     start a paragraph with `<em>`, it will not wrap it in a `<p>` for you.
-///     As soon as it sees something like HTML, it stops mucking with it until
-///     it hits the next block.
-/// 3.  Absolutely no HTML parsing or validation is done. We're a markdown
-///     parser not an HTML parser!
-class BlockHtmlSyntax extends BlockSyntax {
-  RegExp get pattern => _RE_HTML;
-
-  bool get canEndBlock => false;
-
-  Node parse(BlockParser parser) {
-    final childLines = [];
-
-    // Eat until we hit a blank line.
-    while (!parser.isDone && !parser.matches(_RE_EMPTY)) {
-      childLines.add(parser.current);
-      parser.advance();
-    }
-
-    return new Text(childLines.join('\n'));
-  }
-}
-
-class ListItem {
-  bool forceBlock = false;
-  final List<String> lines;
-
-  ListItem(this.lines);
-}
-
-/// Base class for both ordered and unordered lists.
-abstract class ListSyntax extends BlockSyntax {
-  bool get canEndBlock => false;
-
-  String get listTag;
-
-  Node parse(BlockParser parser) {
-    final items = <ListItem>[];
-    var childLines = <String>[];
-
-    endItem() {
-      if (childLines.length > 0) {
-        items.add(new ListItem(childLines));
-        childLines = <String>[];
-      }
-    }
-
-    var match;
-    tryMatch(RegExp pattern) {
-      match = pattern.firstMatch(parser.current);
-      return match != null;
-    }
-
-    bool afterEmpty = false;
-    while (!parser.isDone) {
-      if (tryMatch(_RE_EMPTY)) {
-        // Add a blank line to the current list item.
-        childLines.add('');
-      } else if (tryMatch(_RE_UL) || tryMatch(_RE_OL)) {
-        // End the current list item and start a new one.
-        endItem();
-        childLines.add(match[1]);
-      } else if (tryMatch(_RE_INDENT)) {
-        // Strip off indent and add to current item.
-        childLines.add(match[1]);
-      } else if (BlockSyntax.isAtBlockEnd(parser)) {
-        // Done with the list.
-        break;
-      } else {
-        // Anything else is paragraph text or other stuff that can be in a list
-        // item. However, if the previous item is a blank line, this means we're
-        // done with the list and are starting a new top-level paragraph.
-        if ((childLines.length > 0) && (childLines.last == '')) break;
-        childLines.add(parser.current);
-      }
-      parser.advance();
-    }
-
-    endItem();
-
-    // Markdown, because it hates us, specifies two kinds of list items. If you
-    // have a list like:
-    //
-    // * one
-    // * two
-    //
-    // Then it will insert the conents of the lines directly in the <li>, like:
-    // <ul>
-    //   <li>one</li>
-    //   <li>two</li>
-    // <ul>
-    //
-    // If, however, there are blank lines between the items, each is wrapped in
-    // paragraphs:
-    //
-    // * one
-    //
-    // * two
-    //
-    // <ul>
-    //   <li><p>one</p></li>
-    //   <li><p>two</p></li>
-    // <ul>
-    //
-    // In other words, sometimes we parse the contents of a list item like a
-    // block, and sometimes line an inline. The rules our parser implements are:
-    //
-    // - If it has more than one line, it's a block.
-    // - If the line matches any block parser (BLOCKQUOTE, HEADER, HR, INDENT,
-    //   UL, OL) it's a block. (This is for cases like "* > quote".)
-    // - If there was a blank line between this item and the previous one, it's
-    //   a block.
-    // - If there was a blank line between this item and the next one, it's a
-    //   block.
-    // - Otherwise, parse it as an inline.
-
-    // Remove any trailing empty lines and note which items are separated by
-    // empty lines. Do this before seeing which items are single-line so that
-    // trailing empty lines on the last item don't force it into being a block.
-    for (int i = 0; i < items.length; i++) {
-      for (int j = items[i].lines.length - 1; j > 0; j--) {
-        if (_RE_EMPTY.firstMatch(items[i].lines[j]) != null) {
-          // Found an empty line. Item and one after it are blocks.
-          if (i < items.length - 1) {
-            items[i].forceBlock = true;
-            items[i + 1].forceBlock = true;
-          }
-          items[i].lines.removeLast();
-        } else {
-          break;
-        }
-      }
-    }
-
-    // Convert the list items to Nodes.
-    final itemNodes = <Node>[];
-    for (final item in items) {
-      bool blockItem = item.forceBlock || (item.lines.length > 1);
-
-      // See if it matches some block parser.
-      final blocksInList = [
-        _RE_BLOCKQUOTE,
-        _RE_HEADER,
-        _RE_HR,
-        _RE_INDENT,
-        _RE_UL,
-        _RE_OL
-      ];
-
-      if (!blockItem) {
-        for (final pattern in blocksInList) {
-          if (pattern.firstMatch(item.lines[0]) != null) {
-            blockItem = true;
-            break;
-          }
-        }
-      }
-
-      // Parse the item as a block or inline.
-      if (blockItem) {
-        // Block list item.
-        final children = parser.document.parseLines(item.lines);
-        itemNodes.add(new Element('li', children));
-      } else {
-        // Raw list item.
-        final contents = parser.document.parseInline(item.lines[0]);
-        itemNodes.add(new Element('li', contents));
-      }
-    }
-
-    return new Element(listTag, itemNodes);
-  }
-}
-
-/// Parses unordered lists.
-class UnorderedListSyntax extends ListSyntax {
-  RegExp get pattern => _RE_UL;
-  String get listTag => 'ul';
-}
-
-/// Parses ordered lists.
-class OrderedListSyntax extends ListSyntax {
-  RegExp get pattern => _RE_OL;
-  String get listTag => 'ol';
-}
-
-/// Parses paragraphs of regular text.
-class ParagraphSyntax extends BlockSyntax {
-  bool get canEndBlock => false;
-
-  bool canParse(BlockParser parser) => true;
-
-  Node parse(BlockParser parser) {
-    final childLines = [];
-
-    // Eat until we hit something that ends a paragraph.
-    while (!BlockSyntax.isAtBlockEnd(parser)) {
-      childLines.add(parser.current);
-      parser.advance();
-    }
-
-    final contents = parser.document.parseInline(childLines.join('\n'));
-    return new Element('p', contents);
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart
deleted file mode 100644
index 5494394..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/html_renderer.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2012, 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 markdown;
-
-String renderToHtml(List<Node> nodes) => new HtmlRenderer().render(nodes);
-
-/// Translates a parsed AST to HTML.
-class HtmlRenderer implements NodeVisitor {
-  static final _BLOCK_TAGS = new RegExp(
-      'blockquote|h1|h2|h3|h4|h5|h6|hr|p|pre');
-
-  StringBuffer buffer;
-
-  HtmlRenderer();
-
-  String render(List<Node> nodes) {
-    buffer = new StringBuffer();
-
-    for (final node in nodes) node.accept(this);
-
-    return buffer.toString();
-  }
-
-  void visitText(Text text) {
-    buffer.write(text.text);
-  }
-
-  bool visitElementBefore(Element element) {
-    // Hackish. Separate block-level elements with newlines.
-    if (!buffer.isEmpty &&
-        _BLOCK_TAGS.firstMatch(element.tag) != null) {
-      buffer.write('\n');
-    }
-
-    buffer.write('<${element.tag}');
-
-    // Sort the keys so that we generate stable output.
-    // TODO(rnystrom): This assumes keys returns a fresh mutable
-    // collection.
-    final attributeNames = element.attributes.keys.toList();
-    attributeNames.sort((a, b) => a.compareTo(b));
-    for (final name in attributeNames) {
-      buffer.write(' $name="${element.attributes[name]}"');
-    }
-
-    if (element.isEmpty) {
-      // Empty element like <hr/>.
-      buffer.write(' />');
-      return false;
-    } else {
-      buffer.write('>');
-      return true;
-    }
-  }
-
-  void visitElementAfter(Element element) {
-    buffer.write('</${element.tag}>');
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/src/markdown/inline_parser.dart b/sdk/lib/_internal/dartdoc/lib/src/markdown/inline_parser.dart
deleted file mode 100644
index d3ec7ae..0000000
--- a/sdk/lib/_internal/dartdoc/lib/src/markdown/inline_parser.dart
+++ /dev/null
@@ -1,419 +0,0 @@
-// Copyright (c) 2012, 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 markdown;
-
-/// Maintains the internal state needed to parse inline span elements in
-/// markdown.
-class InlineParser {
-  static List<InlineSyntax>  defaultSyntaxes = <InlineSyntax>[
-    // This first regexp matches plain text to accelerate parsing.  It must
-    // be written so that it does not match any prefix of any following
-    // syntax.  Most markdown is plain text, so it is faster to match one
-    // regexp per 'word' rather than fail to match all the following regexps
-    // at each non-syntax character position.  It is much more important
-    // that the regexp is fast than complete (for example, adding grouping
-    // is likely to slow the regexp down enough to negate its benefit).
-    // Since it is purely for optimization, it can be removed for debugging.
-
-    // TODO(amouravski): this regex will glom up any custom syntaxes unless
-    // they're at the beginning.
-    new TextSyntax(r'\s*[A-Za-z0-9]+'),
-
-    // The real syntaxes.
-
-    new AutolinkSyntax(),
-    new LinkSyntax(),
-    // "*" surrounded by spaces is left alone.
-    new TextSyntax(r' \* '),
-    // "_" surrounded by spaces is left alone.
-    new TextSyntax(r' _ '),
-    // Leave already-encoded HTML entities alone. Ensures we don't turn
-    // "&amp;" into "&amp;amp;"
-    new TextSyntax(r'&[#a-zA-Z0-9]*;'),
-    // Encode "&".
-    new TextSyntax(r'&', sub: '&amp;'),
-    // Encode "<". (Why not encode ">" too? Gruber is toying with us.)
-    new TextSyntax(r'<', sub: '&lt;'),
-    // Parse "**strong**" tags.
-    new TagSyntax(r'\*\*', tag: 'strong'),
-    // Parse "__strong__" tags.
-    new TagSyntax(r'__', tag: 'strong'),
-    // Parse "*emphasis*" tags.
-    new TagSyntax(r'\*', tag: 'em'),
-    // Parse "_emphasis_" tags.
-    // TODO(rnystrom): Underscores in the middle of a word should not be
-    // parsed as emphasis like_in_this.
-    new TagSyntax(r'_', tag: 'em'),
-    // Parse inline code within double backticks: "``code``".
-    new CodeSyntax(r'``\s?((?:.|\n)*?)\s?``'),
-    // Parse inline code within backticks: "`code`".
-    new CodeSyntax(r'`([^`]*)`')
-    // We will add the LinkSyntax once we know about the specific link resolver.
-  ];
-
-  /// The string of markdown being parsed.
-  final String source;
-
-  /// The markdown document this parser is parsing.
-  final Document document;
-
-  List<InlineSyntax> syntaxes;
-
-  /// The current read position.
-  int pos = 0;
-
-  /// Starting position of the last unconsumed text.
-  int start = 0;
-
-  final List<TagState> _stack;
-
-  InlineParser(this.source, this.document)
-    : _stack = <TagState>[] {
-    /// User specified syntaxes will be the first syntaxes to be evaluated.
-    if (document.inlineSyntaxes != null) {
-      syntaxes = [];
-      syntaxes.addAll(document.inlineSyntaxes);
-      syntaxes.addAll(defaultSyntaxes);
-    } else {
-      syntaxes = defaultSyntaxes;
-    }
-    // Custom link resolver goes after the generic text syntax.
-    syntaxes.insert(1, new LinkSyntax(linkResolver: document.linkResolver));
-  }
-
-  List<Node> parse() {
-    // Make a fake top tag to hold the results.
-    _stack.add(new TagState(0, 0, null));
-
-    while (!isDone) {
-      bool matched = false;
-
-      // See if any of the current tags on the stack match. We don't allow tags
-      // of the same kind to nest, so this takes priority over other possible // matches.
-      for (int i = _stack.length - 1; i > 0; i--) {
-        if (_stack[i].tryMatch(this)) {
-          matched = true;
-          break;
-        }
-      }
-      if (matched) continue;
-
-      // See if the current text matches any defined markdown syntax.
-      for (final syntax in syntaxes) {
-        if (syntax.tryMatch(this)) {
-          matched = true;
-          break;
-        }
-      }
-      if (matched) continue;
-
-      // If we got here, it's just text.
-      advanceBy(1);
-    }
-
-    // Unwind any unmatched tags and get the results.
-    return _stack[0].close(this, null);
-  }
-
-  writeText() {
-    writeTextRange(start, pos);
-    start = pos;
-  }
-
-  writeTextRange(int start, int end) {
-    if (end > start) {
-      final text = source.substring(start, end);
-      final nodes = _stack.last.children;
-
-      // If the previous node is text too, just append.
-      if ((nodes.length > 0) && (nodes.last is Text)) {
-        final newNode = new Text('${nodes.last.text}$text');
-        nodes[nodes.length - 1] = newNode;
-      } else {
-        nodes.add(new Text(text));
-      }
-    }
-  }
-
-  addNode(Node node) {
-    _stack.last.children.add(node);
-  }
-
-  // TODO(rnystrom): Only need this because RegExp doesn't let you start
-  // searching from a given offset.
-  String get currentSource => source.substring(pos, source.length);
-
-  bool get isDone => pos == source.length;
-
-  void advanceBy(int length) {
-    pos += length;
-  }
-
-  void consume(int length) {
-    pos += length;
-    start = pos;
-  }
-}
-
-/// Represents one kind of markdown tag that can be parsed.
-abstract class InlineSyntax {
-  final RegExp pattern;
-
-  InlineSyntax(String pattern)
-    : pattern = new RegExp(pattern, multiLine: true);
-
-  bool tryMatch(InlineParser parser) {
-    final startMatch = pattern.firstMatch(parser.currentSource);
-    if ((startMatch != null) && (startMatch.start == 0)) {
-      // Write any existing plain text up to this point.
-      parser.writeText();
-
-      if (onMatch(parser, startMatch)) {
-        parser.consume(startMatch[0].length);
-      }
-      return true;
-    }
-    return false;
-  }
-
-  bool onMatch(InlineParser parser, Match match);
-}
-
-/// Matches stuff that should just be passed through as straight text.
-class TextSyntax extends InlineSyntax {
-  String substitute;
-  TextSyntax(String pattern, {String sub})
-    : super(pattern),
-      substitute = sub;
-
-  bool onMatch(InlineParser parser, Match match) {
-    if (substitute == null) {
-      // Just use the original matched text.
-      parser.advanceBy(match[0].length);
-      return false;
-    }
-
-    // Insert the substitution.
-    parser.addNode(new Text(substitute));
-    return true;
-  }
-}
-
-/// Matches autolinks like `<http://foo.com>`.
-class AutolinkSyntax extends InlineSyntax {
-  AutolinkSyntax()
-    : super(r'<((http|https|ftp)://[^>]*)>');
-  // TODO(rnystrom): Make case insensitive.
-
-  bool onMatch(InlineParser parser, Match match) {
-    final url = match[1];
-
-    final anchor = new Element.text('a', escapeHtml(url));
-    anchor.attributes['href'] = url;
-    parser.addNode(anchor);
-
-    return true;
-  }
-}
-
-/// Matches syntax that has a pair of tags and becomes an element, like `*` for
-/// `<em>`. Allows nested tags.
-class TagSyntax extends InlineSyntax {
-  final RegExp endPattern;
-  final String tag;
-
-  TagSyntax(String pattern, {String tag, String end})
-    : super(pattern),
-      endPattern = new RegExp((end != null) ? end : pattern, multiLine: true),
-      tag = tag;
-    // TODO(rnystrom): Doing this.field doesn't seem to work with named args.
-
-  bool onMatch(InlineParser parser, Match match) {
-    parser._stack.add(new TagState(parser.pos,
-      parser.pos + match[0].length, this));
-    return true;
-  }
-
-  bool onMatchEnd(InlineParser parser, Match match, TagState state) {
-    parser.addNode(new Element(tag, state.children));
-    return true;
-  }
-}
-
-/// Matches inline links like `[blah] [id]` and `[blah] (url)`.
-class LinkSyntax extends TagSyntax {
-  Resolver linkResolver;
-
-  /// The regex for the end of a link needs to handle both reference style and
-  /// inline styles as well as optional titles for inline links. To make that
-  /// a bit more palatable, this breaks it into pieces.
-  static get linkPattern {
-    final refLink    = r'\s?\[([^\]]*)\]';        // "[id]" reflink id.
-    final title      = r'(?:[ ]*"([^"]+)"|)';     // Optional title in quotes.
-    final inlineLink = '\\s?\\(([^ )]+)$title\\)'; // "(url "title")" link.
-    return '\](?:($refLink|$inlineLink)|)';
-
-    // The groups matched by this are:
-    // 1: Will be non-empty if it's either a ref or inline link. Will be empty
-    //    if it's just a bare pair of square brackets with nothing after them.
-    // 2: Contains the id inside [] for a reference-style link.
-    // 3: Contains the URL for an inline link.
-    // 4: Contains the title, if present, for an inline link.
-  }
-
-  LinkSyntax({this.linkResolver})
-    : super(r'\[', end: linkPattern);
-
-  bool onMatchEnd(InlineParser parser, Match match, TagState state) {
-    var url;
-    var title;
-
-    // If we didn't match refLink or inlineLink, then it means there was
-    // nothing after the first square bracket, so it isn't a normal markdown
-    // link at all. Instead, we allow users of the library to specify a special
-    // resolver function ([linkResolver]) that may choose to handle
-    // this. Otherwise, it's just treated as plain text.
-    if ((match[1] == null) || (match[1] == '')) {
-      if (linkResolver == null) return false;
-
-      // Only allow implicit links if the content is just text.
-      // TODO(rnystrom): Do we want to relax this?
-      if (state.children.length != 1) return false;
-      if (state.children[0] is! Text) return false;
-
-      Text link = state.children[0];
-
-      // See if we have a resolver that will generate a link for us.
-      final node = linkResolver(link.text);
-      if (node == null) return false;
-
-      parser.addNode(node);
-      return true;
-    }
-
-    if ((match[3] != null) && (match[3] != '')) {
-      // Inline link like [foo](url).
-      url = match[3];
-      title = match[4];
-
-      // For whatever reason, markdown allows angle-bracketed URLs here.
-      if (url.startsWith('<') && url.endsWith('>')) {
-        url = url.substring(1, url.length - 1);
-      }
-    } else {
-      // Reference link like [foo] [bar].
-      var id = match[2];
-      if (id == '') {
-        // The id is empty ("[]") so infer it from the contents.
-        id = parser.source.substring(state.startPos + 1, parser.pos);
-      }
-
-      // References are case-insensitive.
-      id = id.toLowerCase();
-
-      // Look up the link.
-      final link = parser.document.refLinks[id];
-      // If it's an unknown link just emit plaintext.
-      if (link == null) return false;
-
-      url = link.url;
-      title = link.title;
-    }
-
-    final anchor = new Element('a', state.children);
-    anchor.attributes['href'] = escapeHtml(url);
-    if ((title != null) && (title != '')) {
-      anchor.attributes['title'] = escapeHtml(title);
-    }
-
-    parser.addNode(anchor);
-    return true;
-  }
-}
-
-/// Matches backtick-enclosed inline code blocks.
-class CodeSyntax extends InlineSyntax {
-  CodeSyntax(String pattern)
-    : super(pattern);
-
-  bool onMatch(InlineParser parser, Match match) {
-    parser.addNode(new Element.text('code', escapeHtml(match[1])));
-    return true;
-  }
-}
-
-/// Keeps track of a currently open tag while it is being parsed. The parser
-/// maintains a stack of these so it can handle nested tags.
-class TagState {
-  /// The point in the original source where this tag started.
-  int startPos;
-
-  /// The point in the original source where open tag ended.
-  int endPos;
-
-  /// The syntax that created this node.
-  final TagSyntax syntax;
-
-  /// The children of this node. Will be `null` for text nodes.
-  final List<Node> children;
-
-  TagState(this.startPos, this.endPos, this.syntax)
-    : children = <Node>[];
-
-  /// Attempts to close this tag by matching the current text against its end
-  /// pattern.
-  bool tryMatch(InlineParser parser) {
-    Match endMatch = syntax.endPattern.firstMatch(parser.currentSource);
-    if ((endMatch != null) && (endMatch.start == 0)) {
-      // Close the tag.
-      close(parser, endMatch);
-      return true;
-    }
-
-    return false;
-  }
-
-  /// Pops this tag off the stack, completes it, and adds it to the output.
-  /// Will discard any unmatched tags that happen to be above it on the stack.
-  /// If this is the last node in the stack, returns its children.
-  List<Node> close(InlineParser parser, Match endMatch) {
-    // If there are unclosed tags on top of this one when it's closed, that
-    // means they are mismatched. Mismatched tags are treated as plain text in
-    // markdown. So for each tag above this one, we write its start tag as text
-    // and then adds its children to this one's children.
-    int index = parser._stack.indexOf(this);
-
-    // Remove the unmatched children.
-    final unmatchedTags = parser._stack.sublist(index + 1);
-    parser._stack.removeRange(index + 1, parser._stack.length);
-
-    // Flatten them out onto this tag.
-    for (final unmatched in unmatchedTags) {
-      // Write the start tag as text.
-      parser.writeTextRange(unmatched.startPos, unmatched.endPos);
-
-      // Bequeath its children unto this tag.
-      children.addAll(unmatched.children);
-    }
-
-    // Pop this off the stack.
-    parser.writeText();
-    parser._stack.removeLast();
-
-    // If the stack is empty now, this is the special "results" node.
-    if (parser._stack.length == 0) return children;
-
-    // We are still parsing, so add this to its parent's children.
-    if (syntax.onMatchEnd(parser, endMatch, this)) {
-      parser.consume(endMatch[0].length);
-    } else {
-      // Didn't close correctly so revert to text.
-      parser.start = startPos;
-      parser.advanceBy(endMatch[0].length);
-    }
-
-    return null;
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart b/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
deleted file mode 100755
index ba57411..0000000
--- a/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
+++ /dev/null
@@ -1,532 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/**
- * This library serializes the Dart2Js AST into a compact and easy to use
- * [Element] tree useful for code exploration tools such as DartDoc.
- */
-library universe_serializer;
-
-import 'dartdoc.dart';
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import 'package:path/path.dart' as path;
-import '../../compiler/implementation/mirrors/dart2js_mirror.dart' as dart2js;
-import '../../compiler/implementation/mirrors/mirrors.dart';
-import '../../compiler/implementation/mirrors/mirrors_util.dart';
-import '../../libraries.dart';
-
-String _stripUri(String uri) {
-  String prefix = "/dart/";
-  int start = uri.indexOf(prefix);
-  if (start != -1) {
-    return uri.substring(start + prefix.length);
-  } else {
-    return uri;
-  }
-}
-
-String _escapeId(String id) {
-  return id.replaceAll(new RegExp('[/]'), '#slash');
-}
-
-/**
- * Base class for all elements in the AST.
- */
-class Element {
-  /** Human readable type name for the node. */
-  final String kind;
-  /** Human readable name for the element. */
-  final String name;
-  /** Id for the node that is unique within its parent's children. */
-  final String id;
-  /** Raw text of the comment associated with the Element if any. */
-  final String comment;
-  /** Raw html comment for the Element from MDN. */
-  String mdnCommentHtml;
-  /**
-   * The URL to the page on MDN that content was pulled from for the current
-   * type being documented. Will be `null` if the type doesn't use any MDN
-   * content.
-   */
-  String mdnUrl;
-  /** Children of the node. */
-  List<Element> children;
-  /** Whether the element is private. */
-  final bool isPrivate;
-
-  /**
-   * Uri containing the definition of the element.
-   */
-  String uri;
-  /**
-   * Line in the original source file that starts the definition of the element.
-   */
-  String line;
-
-  // TODO(jacobr): refactor the code so that lookupMdnComment does not need to
-  // be passed to every Element constructor.
-  Element(Mirror mirror, this.kind, this.name, String id, this.comment,
-      MdnComment lookupMdnComment(Mirror))
-      : line = mirror.location.line.toString(),
-        id = _escapeId(id),
-        isPrivate = _optionalBool(mirror.isPrivate),
-        uri = _stripUri(mirror.location.sourceUri.toString()) {
-    if (lookupMdnComment != null) {
-      var mdnComment = lookupMdnComment(mirror);
-      if (mdnComment != null) {
-        mdnCommentHtml = mdnComment.mdnComment;
-        mdnUrl = mdnComment.mdnUrl;
-      }
-    }
-  }
-
-  void addChild(Element child) {
-    if (children == null) {
-      children = <Element>[];
-    }
-    children.add(child);
-  }
-
-  /**
-   * Remove all URIs that exactly match the parent node's URI.
-   * This reduces output file size by about 20%.
-   */
-  void stripDuplicateUris(String parentUri, parentLine) {
-    if (children != null) {
-      for (var child in children) {
-        child.stripDuplicateUris(uri, line);
-      }
-    }
-    if (parentUri == uri) {
-      uri = null;
-    }
-    if (line == parentLine) {
-      line = null;
-    }
-  }
-}
-
-/**
- * Converts false to null.  Useful as the serialization scheme we use
- * omits null values.
- */
-bool _optionalBool(bool value) => value == true ? true : null;
-
-Reference _optionalReference(Mirror mirror) {
-  return (mirror != null && mirror.simpleName != "Dynamic_" &&
-      mirror.simpleName != "dynamic") ?
-        new Reference(mirror) : null;
-}
-
-/**
- * Helper class to track what members of a library should be included.
- */
-class LibrarySubset {
-  final LibraryMirror library;
-  Set<String> includedChildren;
-
-  LibrarySubset(this.library) : includedChildren = new Set<String>();
-}
-
-/**
- * [Element] describing a Dart library.
- */
-class LibraryElement extends Element {
-  /**
-   * Partial versions of LibraryElements containing classes that are extended
-   * or implemented by classes in this library.
-   */
-  List<LibraryElement> dependencies;
-
-  /**
-   * Construct a LibraryElement from a [mirror].
-   *
-   * If [includedChildren] is specified, only elements matching names in
-   * [includedChildren] are included and no dependencies are included.
-   * [lookupMdnComment] is an optional function that returns the MDN
-   * documentation for elements. [dependencies] is an optional map
-   * tracking all classes dependend on by this [ClassElement].
-   */
-  LibraryElement(LibraryMirror mirror,
-      {MdnComment lookupMdnComment(Mirror), Set<String> includedChildren})
-      : super(mirror, 'library', _libraryName(mirror), mirror.simpleName,
-          computeComment(mirror), lookupMdnComment) {
-    var requiredDependencies;
-    // We don't need to track our required dependencies when generating a
-    // filtered version of this library which will be used as a dependency for
-    // another library.
-    if (includedChildren == null)
-      requiredDependencies = new Map<String, LibrarySubset>();
-    mirror.functions.forEach((childName, childMirror) {
-      if (includedChildren == null || includedChildren.contains(childName))
-        addChild(new MethodElement(childName, childMirror, lookupMdnComment));
-    });
-
-    mirror.getters.forEach((childName, childMirror) {
-      if (includedChildren == null || includedChildren.contains(childName))
-        addChild(new GetterElement(childName, childMirror, lookupMdnComment));
-    });
-
-    mirror.variables.forEach((childName, childMirror) {
-      if (includedChildren == null || includedChildren.contains(childName))
-        addChild(new VariableElement(childName, childMirror, lookupMdnComment));
-    });
-
-    mirror.classes.forEach((className, classMirror) {
-      if (includedChildren == null || includedChildren.contains(className)) {
-        if (classMirror is TypedefMirror) {
-          addChild(new TypedefElement(className, classMirror));
-        } else {
-          addChild(new ClassElement(classMirror,
-              dependencies: requiredDependencies,
-              lookupMdnComment: lookupMdnComment));
-        }
-      }
-    });
-
-    if (requiredDependencies != null && !requiredDependencies.isEmpty) {
-      dependencies = requiredDependencies.values.map((librarySubset) =>
-          new LibraryElement(
-              librarySubset.library,
-              lookupMdnComment: lookupMdnComment,
-              includedChildren: librarySubset.includedChildren)).toList();
-    }
-  }
-
-  static String _libraryName(LibraryMirror mirror) {
-    if (mirror.uri.scheme == 'file') {
-      // TODO(jacobr): this is a hack. Remove once these libraries are removed
-      // from the sdk.
-      var uri = mirror.uri;
-      var uriPath = uri.path;
-
-      var parts = path.split(uriPath);
-
-      // Find either pkg/ or packages/
-      var pkgDir = parts.lastIndexOf('pkg');
-      var packageDir = parts.lastIndexOf('packages');
-
-      if (pkgDir >= 0) {
-        packageDir = pkgDir;
-      }
-
-      var libDir = parts.lastIndexOf('lib');
-      var rest = parts.sublist(libDir + 1);
-
-      // If there's no lib, we can't find the package.
-      if (libDir < 0 || libDir < packageDir) {
-        // TODO(jacobr): this is a lousy fallback.
-        print("Unable to determine package for $uriPath.");
-        return mirror.uri.toString();
-      } else if (packageDir >= 0 && rest.length >= 1) {
-        // For URI: foo/bar/packages/widget/lib/sprocket.dart will return:
-        // 'package:widget/sprocket.dart'
-        return 'package:${parts[packageDir + 1]}/${rest.join('/')}';
-      }
-    } else {
-      return mirror.uri.toString();
-    }
-  }
-
-  void stripDuplicateUris(String parentUri, parentLine) {
-    super.stripDuplicateUris(parentUri, parentLine);
-
-    if (dependencies != null) {
-      for (var child in dependencies) {
-        child.stripDuplicateUris(null, null);
-      }
-    }
-  }
-}
-
-/**
- * Returns whether the class implements or extends [Error] or [Exception].
- */
-bool _isThrowable(ClassMirror mirror) {
-  if (mirror.library.uri.toString() == 'dart:core' &&
-      mirror.simpleName == 'Error' || mirror.simpleName == 'Exception')
-    return true;
-  if (mirror.superclass != null && _isThrowable(mirror.superclass))
-    return true;
-  return mirror.superinterfaces.any(_isThrowable);
-}
-
-/**
- * [Element] describing a Dart class.
- */
-class ClassElement extends Element {
-  /** Base class.*/
-  final Reference superclass;
-  /** Whether the class is abstract. */
-  final bool isAbstract;
-  /** Interfaces the class implements. */
-  List<Reference> interfaces;
-  /** Whether the class implements or extends [Error] or [Exception]. */
-  bool isThrowable;
-
-  /**
-   * Constructs a [ClassElement] from a [ClassMirror].
-   *
-   * [dependencies] is an optional map updated as a side effect of running
-   * this constructor that tracks what classes from other libraries are
-   * dependencies of classes in this library.  A class is considered a
-   * dependency if it implements or extends another class.
-   * [lookupMdnComment] is an optional function that returns the MDN
-   * documentation for elements. [dependencies] is an optional map
-   * tracking all classes dependend on by this [ClassElement].
-   */
-  ClassElement(ClassMirror mirror,
-      {Map<String, LibrarySubset> dependencies,
-       MdnComment lookupMdnComment(Mirror)})
-      : super(mirror, 'class', mirror.simpleName, mirror.simpleName, computeComment(mirror),
-          lookupMdnComment),
-        superclass = _optionalReference(mirror.superclass),
-        isAbstract = _optionalBool(mirror.isAbstract),
-        isThrowable = _optionalBool(_isThrowable(mirror)){
-
-    addCrossLibraryDependencies(clazz) {
-      if (clazz == null) return;
-
-      if (mirror.library != clazz.library) {
-        var libraryStub = dependencies.putIfAbsent(clazz.library.simpleName,
-            () => new LibrarySubset(clazz.library));
-        libraryStub.includedChildren.add(clazz.simpleName);
-      }
-
-      for (var interface in clazz.superinterfaces) {
-        addCrossLibraryDependencies(interface);
-      }
-      addCrossLibraryDependencies(clazz.superclass);
-    }
-
-    if (dependencies != null) {
-      addCrossLibraryDependencies(mirror);
-    }
-
-    for (var interface in mirror.superinterfaces) {
-      if (this.interfaces == null) {
-        this.interfaces = <Reference>[];
-      }
-      this.interfaces.add(_optionalReference(interface));
-    }
-
-    mirror.methods.forEach((childName, childMirror) {
-      if (!childMirror.isConstructor && !childMirror.isGetter) {
-        addChild(new MethodElement(childName, childMirror, lookupMdnComment));
-      }
-    });
-
-    mirror.getters.forEach((childName, childMirror) {
-      addChild(new GetterElement(childName, childMirror, lookupMdnComment));
-    });
-
-    mirror.variables.forEach((childName, childMirror) {
-        addChild(new VariableElement(childName, childMirror,
-            lookupMdnComment));
-    });
-
-    mirror.constructors.forEach((constructorName, methodMirror) {
-      addChild(new MethodElement(constructorName, methodMirror,
-          lookupMdnComment, 'constructor'));
-    });
-
-    for (var typeVariable in mirror.originalDeclaration.typeVariables) {
-      addChild(new TypeParameterElement(typeVariable));
-    }
-  }
-}
-
-/**
- * [Element] describing a getter.
- */
-class GetterElement extends Element {
-  /** Type of the getter. */
-  final Reference ref;
-  final bool isStatic;
-
-  GetterElement(String name, MethodMirror mirror,
-      MdnComment lookupMdnComment(Mirror))
-      : super(mirror, 'property', mirror.simpleName, name, computeComment(mirror),
-          lookupMdnComment),
-        ref = _optionalReference(mirror.returnType),
-        isStatic = _optionalBool(mirror.isStatic);
-}
-
-/**
- * [Element] describing a method which may be a regular method, a setter, or an
- * operator.
- */
-class MethodElement extends Element {
-  final Reference returnType;
-  final bool isSetter;
-  final bool isOperator;
-  final bool isStatic;
-
-  MethodElement(String name, MethodMirror mirror,
-      MdnComment lookupMdnComment(Mirror), [String kind = 'method'])
-      : super(mirror, kind, name, '$name${mirror.parameters.length}()',
-              computeComment(mirror), lookupMdnComment),
-        returnType = _optionalReference(mirror.returnType),
-        isSetter = _optionalBool(mirror.isSetter),
-        isOperator = _optionalBool(mirror.isOperator),
-        isStatic = _optionalBool(mirror.isStatic) {
-
-    for (var param in mirror.parameters) {
-      addChild(new ParameterElement(param));
-    }
-  }
-}
-
-/**
- * Element describing a parameter.
- */
-class ParameterElement extends Element {
-  /** Type of the parameter. */
-  final Reference ref;
-
-  /**
-   * Returns the default value for this parameter.
-   */
-  final String defaultValue;
-
-  /**
-   * Is this parameter optional?
-   */
-  final bool isOptional;
-
-  /**
-   * Is this parameter named?
-   */
-  final bool isNamed;
-
-  /**
-   * Returns the initialized field, if this parameter is an initializing formal.
-   */
-  final Reference initializedField;
-
-  ParameterElement(ParameterMirror mirror)
-      : super(mirror, 'param', mirror.simpleName, mirror.simpleName, null,
-          null),
-        ref = _optionalReference(mirror.type),
-        isOptional = _optionalBool(mirror.isOptional),
-        defaultValue = mirror.defaultValue,
-        isNamed = _optionalBool(mirror.isNamed),
-        initializedField = _optionalReference(mirror.initializedField) {
-
-    if (mirror.type is FunctionTypeMirror) {
-      addChild(new FunctionTypeElement(mirror.type));
-    }
-  }
-}
-
-class FunctionTypeElement extends Element {
-  final Reference returnType;
-
-  FunctionTypeElement(FunctionTypeMirror mirror)
-      : super(mirror, 'functiontype', mirror.simpleName, mirror.simpleName, null, null),
-        returnType = _optionalReference(mirror.returnType) {
-    for (var param in mirror.parameters) {
-      addChild(new ParameterElement(param));
-    }
-    // TODO(jacobr): can a FunctionTypeElement really have type variables?
-    for (var typeVariable in mirror.originalDeclaration.typeVariables) {
-      addChild(new TypeParameterElement(typeVariable));
-    }
-  }
-}
-
-/**
- * Element describing a generic type parameter.
- */
-class TypeParameterElement extends Element {
-  /**
-   * Upper bound for the parameter.
-   *
-   * In the following code sample, [:Bar:] is an upper bound:
-   * [: class Bar<T extends Foo> { } :]
-   */
-  final Reference upperBound;
-
-  TypeParameterElement(TypeMirror mirror)
-      : super(mirror, 'typeparam', mirror.simpleName, mirror.simpleName, null,
-          null),
-        upperBound = mirror.upperBound != null && !mirror.upperBound.isObject ?
-            new Reference(mirror.upperBound) : null;
-}
-
-/**
- * Element describing a variable.
- */
-class VariableElement extends Element {
-  /** Type of the variable. */
-  final Reference ref;
-  /** Whether the variable is static. */
-  final bool isStatic;
-  /** Whether the variable is final. */
-  final bool isFinal;
-
-  VariableElement(String name, VariableMirror mirror,
-      MdnComment lookupMdnComment(Mirror))
-      : super(mirror, 'variable', mirror.simpleName, name,
-          computeComment(mirror), lookupMdnComment),
-        ref = _optionalReference(mirror.type),
-        isStatic = _optionalBool(mirror.isStatic),
-        isFinal = _optionalBool(mirror.isFinal);
-}
-
-/**
- * Element describing a typedef.
- */
-
-class TypedefElement extends Element {
-  /** Return type of the typedef. */
-  final Reference returnType;
-
-  TypedefElement(String name, TypedefMirror mirror)
-      : super(mirror, 'typedef', mirror.simpleName, name,
-               computeComment(mirror), null),
-        returnType = _optionalReference(mirror.value.returnType) {
-    for (var param in mirror.value.parameters) {
-      addChild(new ParameterElement(param));
-    }
-    for (var typeVariable in mirror.originalDeclaration.typeVariables) {
-      addChild(new TypeParameterElement(typeVariable));
-    }
-  }
-}
-
-/**
- * Reference to an Element with type argument if the reference is parameterized.
- */
-class Reference {
-  final String name;
-  final String refId;
-  List<Reference> arguments;
-
-  Reference(Mirror mirror)
-      : name = displayName(mirror),
-        refId = getId(mirror) {
-    if (mirror is ClassMirror) {
-      if (mirror is !TypedefMirror && !mirror.typeArguments.isEmpty) {
-        arguments = <Reference>[];
-        for (var typeArg in mirror.typeArguments) {
-          arguments.add(_optionalReference(typeArg));
-        }
-      }
-    }
-  }
-
-  // TODO(jacobr): compute the referenceId correctly for the general case so
-  // that this method can work with all element types not just LibraryElements.
-  Reference.fromElement(LibraryElement e) : name = e.name, refId = e.id;
-
-  static String getId(Mirror mirror) {
-    String id = _escapeId(mirror.simpleName);
-    if (mirror.owner != null) {
-      id = '${getId(mirror.owner)}/$id';
-    }
-    return id;
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/pubspec.yaml b/sdk/lib/_internal/dartdoc/pubspec.yaml
deleted file mode 100644
index fe775e4..0000000
--- a/sdk/lib/_internal/dartdoc/pubspec.yaml
+++ /dev/null
@@ -1,10 +0,0 @@
-name: dartdoc
-description: >
- Libraries for generating documentation from Dart source code.
-
-dependencies:
-  args: ">=0.4.2 <1.0.0"
-  path: ">=0.4.2 <1.0.0"
-
-dev_dependencies:
-  unittest: ">=0.4.2 <1.0.0"
diff --git a/sdk/lib/_internal/dartdoc/static/body-bg.png b/sdk/lib/_internal/dartdoc/static/body-bg.png
deleted file mode 100644
index 4fe447c..0000000
--- a/sdk/lib/_internal/dartdoc/static/body-bg.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/class.png b/sdk/lib/_internal/dartdoc/static/class.png
deleted file mode 100644
index 214fc21..0000000
--- a/sdk/lib/_internal/dartdoc/static/class.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/content-bg.png b/sdk/lib/_internal/dartdoc/static/content-bg.png
deleted file mode 100644
index e5320c7..0000000
--- a/sdk/lib/_internal/dartdoc/static/content-bg.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/dart-logo-small.png b/sdk/lib/_internal/dartdoc/static/dart-logo-small.png
deleted file mode 100644
index f6d9791..0000000
--- a/sdk/lib/_internal/dartdoc/static/dart-logo-small.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/exception.png b/sdk/lib/_internal/dartdoc/static/exception.png
deleted file mode 100644
index ee0815a..0000000
--- a/sdk/lib/_internal/dartdoc/static/exception.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/external-link.png b/sdk/lib/_internal/dartdoc/static/external-link.png
deleted file mode 100644
index 0d847d7..0000000
--- a/sdk/lib/_internal/dartdoc/static/external-link.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/favicon.ico b/sdk/lib/_internal/dartdoc/static/favicon.ico
deleted file mode 100644
index 50ea5b0..0000000
--- a/sdk/lib/_internal/dartdoc/static/favicon.ico
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/header-bg.png b/sdk/lib/_internal/dartdoc/static/header-bg.png
deleted file mode 100644
index 9cadb55..0000000
--- a/sdk/lib/_internal/dartdoc/static/header-bg.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/interface.png b/sdk/lib/_internal/dartdoc/static/interface.png
deleted file mode 100644
index 421a07b..0000000
--- a/sdk/lib/_internal/dartdoc/static/interface.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/library.png b/sdk/lib/_internal/dartdoc/static/library.png
deleted file mode 100644
index eb20c8e..0000000
--- a/sdk/lib/_internal/dartdoc/static/library.png
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/dartdoc/static/styles.css b/sdk/lib/_internal/dartdoc/static/styles.css
deleted file mode 100644
index c9813c8..0000000
--- a/sdk/lib/_internal/dartdoc/static/styles.css
+++ /dev/null
@@ -1,487 +0,0 @@
-/* Reset */
-body, h1, h2, h3, h4, li, ol, p, pre, section, ul {
-  margin: 0;
-  padding: 0;
-}
-
-body {
-  font-family: Georgia, serif;
-  background: #e8e8e8;
-  color: #333;
-  background-image: url('body-bg.png');
-  background-repeat: repeat;
-}
-
-h2 {
-  font: 400 28px/44px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-}
-
-h3 {
-  font: 600 14px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  color: #999;
-  margin: 22px 0 0 0;
-}
-
-h4 {
-  font: 600 16px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-}
-
-p {
-  font-size: 16px;
-  line-height: 22px;
-  margin: 0 0 22px 0;
-}
-
-h3 + p {
-  /* Text immediately following a subheader should be snug with it. */
-  margin-top: 0;
-}
-
-strong {
-  font-weight: 700;
-}
-
-pre, code {
-  font: 14px/22px Menlo, Monaco, Consolas, Courier, monospace;
-  color: hsl(220, 20%, 30%);
-  background: hsl(220, 20%, 95%);
-  margin: 22px 0;
-  padding: 0 4px;
-  border-radius: 4px;
-  overflow-x:auto;
-  overflow-y:hidden;
-}
-
-pre > code {
-  padding: 0;
-}
-
-a {
-  color: #15c;
-  text-decoration: none;
-}
-
-a:hover {
-  text-decoration: underline;
-}
-
-a:visited {
-  color: #15c;
-}
-
-li {
-  font-size: 16px;
-  line-height: 22px;
-}
-
-/* First paragraph in an li is snug, but others are spaced out. */
-li p:first-child {
-  margin: 0 0 0 0;
-}
-
-li > p {
-  margin: 22px 0 0 0;
-}
-
-ol, ul {
-  padding-left: 22px;
-}
-
-hr {
-  border: none;
-  height: 1px;
-  background: #ccc;
-  margin: 22px 0 21px 0;
-}
-
-hr + h2 {
-  margin-top: 21px; /* To compensate for the thickness of the hr. */
-}
-
-.page {
-  max-width: 1000px;
-  background: #fff;
-  margin: 0 auto 22px auto;
-  border: solid 1px #ccc;
-  border-top: none;
-  box-shadow: 0 0 50px #888;
-
-  background-image: url('content-bg.png');
-  background-repeat: repeat-y;
-
-  position: relative;
-}
-
-.header {
-  background: #333;
-  background-image: url('header-bg.png');
-  height: 44px;
-  color: hsl(0, 0%, 50%);
-  font: 400 15px/44px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-}
-
-.header .logo {
-  background-image: url('dart-logo-small.png');
-  width: 66px;
-  height: 44px;
-  float: left;
-}
-
-.header a {
-  color: hsl(0, 0%, 80%);
-}
-
-.header a:hover {
-  color: hsl(0, 0%, 100%);
-}
-
-.header #search-box {
-  display: inline;
-  float: right;
-  margin-right: 11px;
-}
-
-.search-input, .drop-down {
-  font: 400 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  width: 300px;
-}
-
-.drop-down {
-  visibility: hidden;
-  z-index: 1000;
-  position: absolute;
-  right: 10px;
-  top: 36px;
-  border: 1px #CCC solid;
-  background-color: white;
-  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-  -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
-}
-
-.drop-down-table {
-  width: 100%;
-}
-
-.drop-down-link-tr {
-  padding: 4px 0px;
-  cursor: pointer;
-}
-.drop-down-link-td {
-  border-bottom: 1px solid #EEE;
-}
-
-.drop-down-link-tr:hover {
-  background: #EEE;
-  color: #333;
-}
-
-.drop-down-link-select {
-  background: #15C;
-  color: white;
-}
-
-.drop-down-link-select:hover {
-  background: #2AF;
-  color: white;
-}
-
-.drop-down-link-kind, .drop-down-link-library {
-  font: 400 10px/10px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-}
-
-.drop-down-link-library {
-  text-align: right;
-}
-
-.drop-down-link-highlight {
-  font-weight:bold;
-}
-
-.nav {
-  float: left;
-  width: 263px; /* 12 x 22px - 1 for border */
-  padding: 0 22px;
-  overflow: hidden;
-  background: #f4f4f4;
-  border-right: solid 1px #ccc;
-}
-
-.nav h2 {
-  font: 400 16px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  margin: 0 -21px;
-  padding: 11px 22px;
-
-  /* Using http://www.colorzilla.com/gradient-editor/ */
-  background: -moz-linear-gradient(top, hsla(0,0%,0%,0.05) 0%, hsla(0,0%,0%,0) 100%);
-  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,hsla(0,0%,0%,0.05)), color-stop(100%,hsla(0,0%,0%,0)));
-  background: -webkit-linear-gradient(top, hsla(0,0%,0%,0.05) 0%,hsla(0,0%,0%,0) 100%);
-  background: -o-linear-gradient(top, hsla(0,0%,0%,0.05) 0%,hsla(0,0%,0%,0) 100%);
-  background: -ms-linear-gradient(top, hsla(0,0%,0%,0.05) 0%,hsla(0,0%,0%,0) 100%);
-  background: linear-gradient(top, hsla(0,0%,0%,0.05) 0%,hsla(0,0%,0%,0) 100%);
-}
-
-ul.icon {
-  margin: 0 0 22px 0;
-  padding: 0;
-}
-
-ul.icon li {
-  font: 600 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  list-style-type: none;
-  white-space: nowrap;
-}
-
-/* Indent nested lists. */
-ul.icon ul {
-  margin-left: 22px;
-}
-
-.icon-class,
-.icon-exception,
-.icon-interface {
-  display: inline-block;
-  width: 14px;
-  height: 14px;
-  margin: 5px 10px 0 2px;
-  vertical-align: top;
-}
-
-.icon-class     { background: url('class.png');     }
-.icon-exception { background: url('exception.png'); }
-.icon-interface { background: url('interface.png'); }
-
-.icon-library {
-  background: url('library.png');
-  width: 16px;
-  height: 14px;
-  display: inline-block;
-  margin: 4px 8px 0 0;
-  vertical-align: top;
-}
-
-.type-box {
-  display: inline-block;
-  font: 600 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  background: #f4f4f4;
-  padding: 0 6px 0 3px;
-  border-radius: 4px;
-}
-
-.type-box .icon-class,
-.type-box .icon-exception,
-.type-box .icon-interface {
-  /* Make a little snugger with the text. */
-  margin-right: 5px;
-}
-
-.content {
-  margin-left: 308px; /* 14 x 22 */
-  padding: 22px 22px;
-}
-
-.clear {
-  clear: both;
-}
-
-.footer {
-  max-width: 956px; /* 1000 - 22 - 22 */
-  text-align: center;
-  margin: 22px auto;
-  color: #888;
-}
-
-.footer p {
-  font: 400 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-}
-
-.inherited {
-}
-
-.inherited-from {
-  font: 400 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  text-align: right;
-  opacity: 0.7;
-}
-
-.inherited-from, .docs-inherited-from {
-  font: 400 13px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  text-align: right;
-  opacity: 0.7;
-}
-
-.docs-inherited-from {
-  margin-top: -22px;
-}
-
-.method .doc,
-.field .doc {
-  padding-left: 44px;
-  /* Ensure there is some space between members with no documentation. */
-  margin-bottom: 22px;
-}
-
-.param {
-  font: 600 14px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-}
-
-.crossref {
-  font: 600 15px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-}
-
-.doc h1 {
-  font: 700 17px/22px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  color: #666;
-}
-
-.doc h2 {
-  font: 600 16px/22px 'Open Sans', 'Lucida Sans Unicode',
-      'Lucida Grande', sans-serif;
-  color: #666;
-}
-
-/* Style external links in docs differently. */
-.doc a[href^="http:"]:after,
-.doc a[href^="https:"]:after {
-  content: url('external-link.png');
-}
-
-/* Highlight members on hover so you can see which docs are for which member. */
-.method:hover,
-.field:hover {
-  margin: 0 -22px;
-  border: solid 4px hsl(40, 100%, 85%);
-  padding: 0 18px;
-  border-top: none;
-  border-bottom: none;
-}
-
-/* Only show the "code" link for the highlighted member. */
-.show-code, .show-inherited {
-  float: right;
-  font: 600 11px 'Open Sans', 'Lucida Sans Unicode', 'Lucida Grande',
-      sans-serif;
-  padding: 0 0 0 6px; /* In case it gets too close to the member. */
-  border: none;
-  background: transparent;
-  margin: 0;
-}
-
-.method:hover .show-code,
-.field:hover .show-code {
-  display: inline;
-}
-
-/* Only show permalinks when hovered over. */
-.anchor-link {
-  display: none;
-}
-
-h2:hover > .anchor-link,
-h4:hover > .anchor-link {
-  display: inline;
-}
-
-/* Only show code when expanded. */
-pre.source {
-  display: none;
-}
-
-pre.source.expanded {
-  display: block;
-}
-
-/* Links that don't cause a page refresh. */
-.anchor-link, .anchor-link:visited,
-.show-code, .show-code:visited,
-.show-inherited, .show-inherited:visited {
-  color: hsl(40, 100%, 40%);
-  cursor: pointer;
-}
-
-.anchor-link, .anchor-link:visited,
-.show-code, .show-code:visited {
-  display: none;
-}
-
-.anchor-link:hover,
-.show-code:hover,
-.show-inherited:hover {
-  color: hsl(40, 100%, 60%);
-}
-
-/* Syntax highlighting. */
-/* Note: these correspond to the constants in classify.dart. */
-.doc pre .e, pre.source .e { color: hsl(  0, 100%, 70%); } /* Error */
-.doc pre .c, pre.source .c { color: hsl(220,  20%, 65%); } /* Comment */
-.doc pre .i, pre.source .i { color: hsl(220,  20%, 20%); } /* Identifier */
-.doc pre .k, pre.source .k { color: hsl(220, 100%, 50%); } /* Keyword */
-.doc pre .p, pre.source .p { color: hsl(220,  20%, 50%); } /* Punctuation */
-.doc pre .o, pre.source .o { color: hsl(220,  40%, 50%); } /* Operator */
-.doc pre .s, pre.source .s { color: hsl( 40,  90%, 40%); } /* String */
-.doc pre .n, pre.source .n { color: hsl( 30,  70%, 50%); } /* Number */
-.doc pre .t, pre.source .t { color: hsl(180,  40%, 40%); } /* Type Name */
-.doc pre .r, pre.source .r { color: hsl(200, 100%, 50%); } /* Special Identifier */
-.doc pre .a, pre.source .a { color: hsl(220, 100%, 45%); } /* Arrow */
-
-/* Interpolated expressions within strings. */
-.doc pre .si, pre.source .si {
-  background: hsl(40, 100%, 90%);
-}
-
-.doc pre .s.si, pre.source .s.si { background: hsl(40, 80%, 95%); }
-.doc pre .i.si, pre.source .i.si { color: hsl(40, 30%, 30%); }
-.doc pre .p.si, pre.source .p.si { color: hsl(40, 60%, 40%); }
-
-/* Enable these to debug the grid: */
-
-/*
-body {
-  background: -webkit-linear-gradient(top, #eee 0, #fff 10%, #fff 90%, #eee 100%);
-  background-size: 22px 22px;
-  background-repeat: repeat;
-}
-
-.page {
-  background: none;
-}
-
-h1 {
-  border-left: solid 4px green;
-}
-
-h2 {
-  border-left: solid 4px blue;
-}
-
-h3 {
-  border-left: solid 4px red;
-}
-
-h4 {
-  border-left: solid 4px orange;
-}
-
-p {
-  border-left: solid 4px purple;
-}
-
-section {
-  border-left: solid 4px gray;
-}
-*/
diff --git a/sdk/lib/_internal/dartdoc/test/dartdoc_search_test.dart b/sdk/lib/_internal/dartdoc/test/dartdoc_search_test.dart
deleted file mode 100644
index 9374c06..0000000
--- a/sdk/lib/_internal/dartdoc/test/dartdoc_search_test.dart
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2012, 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.
-
-library dartdoc_search_test;
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../../../../../pkg/expect/lib/expect.dart';
-import '../lib/src/dartdoc/nav.dart';
-import '../lib/src/client/search.dart';
-
-const String URL = 'dummy-url';
-
-testTopLevelVsMembers() {
-	var search = new SearchText('timer');
-	var match = obtainMatch(search, 'timer');
-	// Matching a top-level field 'timer';
-	var topLevelResult = new Result(match, FIELD, URL);
-	// Matching a member field 'timer' in 'Foo';
-	var memberResult = new Result(match, FIELD, URL, type: 'Foo');
-	Expect.equals(-1, resultComparator(topLevelResult, memberResult),
-		"Top level fields should be preferred to member fields");
-}
-
-testTopLevelFullVsPrefix() {
-	var search = new SearchText('cancel');
-	var fullMatch = obtainMatch(search, 'cancel');
-	var prefixMatch = obtainMatch(search, 'cancelable');
-	// Matching a top-level method 'cancel';
-	var fullResult = new Result(fullMatch, METHOD, URL);
-	// Matching a top-level method 'cancelable';
-	var prefixResult = new Result(prefixMatch, METHOD, URL);
-	Expect.equals(-1, resultComparator(fullResult, prefixResult),
-		"Full matches should be preferred to prefix matches");
-}
-
-testMemberFullVsPrefix() {
-	var search = new SearchText('cancel');
-	var fullMatch = obtainMatch(search, 'cancel');
-	var prefixMatch = obtainMatch(search, 'cancelable');
-	// Matching a member method 'cancel' in 'Isolate';
-	var fullResult = new Result(fullMatch, METHOD, URL, type: 'Isolate');
-	// Matching a member field 'cancelable' in 'Event';
-	var prefixResult = new Result(prefixMatch, FIELD, URL, type: 'Event');
-	Expect.equals(-1, resultComparator(fullResult, prefixResult),
-		"Full matches should be preferred to prefix matches");
-}
-
-void main() {
-	testTopLevelVsMembers();
-	testTopLevelFullVsPrefix();
-	testMemberFullVsPrefix();
-}
diff --git a/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart b/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart
deleted file mode 100644
index 0bc58a3..0000000
--- a/sdk/lib/_internal/dartdoc/test/dartdoc_test.dart
+++ /dev/null
@@ -1,284 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/// Unit tests for doc.
-library dartdocTests;
-
-import 'dart:async';
-import 'dart:io';
-
-import 'package:path/path.dart' as path;
-import 'package:unittest/unittest.dart';
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../lib/dartdoc.dart' as dd;
-import '../lib/markdown.dart';
-import 'markdown_test.dart';
-
-main() {
-  // Some tests take more than the default 20 second unittest timeout.
-  unittestConfiguration.timeout = null;
-  group('isAbsolute', () {
-    final doc = new dd.Dartdoc();
-
-    test('returns false if there is no scheme', () {
-      expect(doc.isAbsolute('index.html'), isFalse);
-      expect(doc.isAbsolute('foo/index.html'), isFalse);
-      expect(doc.isAbsolute('foo/bar/index.html'), isFalse);
-    });
-
-    test('returns true if there is a scheme', () {
-      expect(doc.isAbsolute('http://google.com'), isTrue);
-      expect(doc.isAbsolute('hTtPs://google.com'), isTrue);
-      expect(doc.isAbsolute('mailto:fake@email.com'), isTrue);
-    });
-  });
-
-  group('relativePath', () {
-    final doc = new dd.Dartdoc();
-
-    test('absolute path is unchanged', () {
-      doc.startFile('dir/sub/file.html');
-      expect(doc.relativePath('http://foo.com'), equals('http://foo.com'));
-    });
-
-    test('from root to root', () {
-      doc.startFile('root.html');
-      expect(doc.relativePath('other.html'), equals('other.html'));
-    });
-
-    test('from root to directory', () {
-      doc.startFile('root.html');
-      expect(doc.relativePath('dir/file.html'), equals('dir/file.html'));
-    });
-
-    test('from root to nested', () {
-      doc.startFile('root.html');
-      expect(doc.relativePath('dir/sub/file.html'), equals(
-          'dir/sub/file.html'));
-    });
-
-    test('from directory to root', () {
-      doc.startFile('dir/file.html');
-      expect(doc.relativePath('root.html'), equals('../root.html'));
-    });
-
-    test('from nested to root', () {
-      doc.startFile('dir/sub/file.html');
-      expect(doc.relativePath('root.html'), equals('../../root.html'));
-    });
-
-    test('from dir to dir with different path', () {
-      doc.startFile('dir/file.html');
-      expect(doc.relativePath('other/file.html'), equals('../other/file.html'));
-    });
-
-    test('from nested to nested with different path', () {
-      doc.startFile('dir/sub/file.html');
-      expect(doc.relativePath('other/sub/file.html'), equals(
-          '../../other/sub/file.html'));
-    });
-
-    test('from nested to directory with different path', () {
-      doc.startFile('dir/sub/file.html');
-      expect(doc.relativePath('other/file.html'), equals(
-          '../../other/file.html'));
-    });
-  });
-
-  group('dartdoc markdown', () {
-    group('[::] blocks', () {
-
-      validateDartdocMarkdown('simple case', '''
-        before [:source:] after
-        ''', '''
-        <p>before <code>source</code> after</p>
-        ''');
-
-      validateDartdocMarkdown('unmatched [:', '''
-        before [: after
-        ''', '''
-        <p>before [: after</p>
-        ''');
-      validateDartdocMarkdown('multiple spans in one text', '''
-        a [:one:] b [:two:] c
-        ''', '''
-        <p>a <code>one</code> b <code>two</code> c</p>
-        ''');
-
-      validateDartdocMarkdown('multi-line', '''
-        before [:first
-        second:] after
-        ''', '''
-        <p>before <code>first
-        second</code> after</p>
-        ''');
-
-      validateDartdocMarkdown('contain backticks', '''
-        before [:can `contain` backticks:] after
-        ''', '''
-        <p>before <code>can `contain` backticks</code> after</p>
-        ''');
-
-      validateDartdocMarkdown('contain double backticks', '''
-        before [:can ``contain`` backticks:] after
-        ''', '''
-        <p>before <code>can ``contain`` backticks</code> after</p>
-        ''');
-
-      validateDartdocMarkdown('contain backticks with spaces', '''
-        before [: `tick` :] after
-        ''', '''
-        <p>before <code>`tick`</code> after</p>
-        ''');
-
-      validateDartdocMarkdown('multiline with spaces', '''
-        before [:in `tick`
-        another:] after
-        ''', '''
-        <p>before <code>in `tick`
-        another</code> after</p>
-        ''');
-
-      validateDartdocMarkdown('ignore markup inside code', '''
-        before [:*b* _c_:] after
-        ''', '''
-        <p>before <code>*b* _c_</code> after</p>
-        ''');
-
-      validateDartdocMarkdown('escape HTML characters', '''
-        [:<&>:]
-        ''', '''
-        <p><code>&lt;&amp;&gt;</code></p>
-        ''');
-
-      validateDartdocMarkdown('escape HTML tags', '''
-        '*' [:<em>:]
-        ''', '''
-        <p>'*' <code>&lt;em&gt;</code></p>
-        ''');
-    });
-  });
-
-  group('integration tests', () {
-    test('no entrypoints', () {
-      _testRunDartDoc([], (result) {
-            expect(result.exitCode, 1);
-          });
-    });
-
-    test('entrypoint in lib', () {
-      _testRunDartDoc(['test_files/lib/no_package_test_file.dart'], (result) {
-        expect(result.exitCode, 0);
-        _expectDocumented(result.stdout, libCount: 1, typeCount: 1, memberCount: 0);
-      });
-    });
-
-    test('entrypoint somewhere with packages locally', () {
-      _testRunDartDoc(['test_files/package_test_file.dart'], (result) {
-        expect(result.exitCode, 0);
-        _expectDocumented(result.stdout, libCount: 1, typeCount: 1, memberCount: 0);
-      });
-    });
-
-    test('file does not exist', () {
-      _testRunDartDoc(['test_files/this_file_does_not_exist.dart'], (result) {
-        expect(result.exitCode, 1);
-      });
-    });
-  });
-}
-
-void _testRunDartDoc(List<String> libraryPaths, void eval(ProcessResult)) {
-  expect(_runDartdoc(libraryPaths).then(eval), completes);
-}
-
-/// The path to the root directory of the dartdoc entrypoint.
-String get _dartdocDir {
-  var dir = path.absolute(Platform.script.toFilePath());
-  while (path.basename(dir) != 'dartdoc') {
-    if (!path.absolute(dir).contains('dartdoc') || dir == path.dirname(dir)) {
-      fail('Unable to find root dartdoc directory.');
-    }
-    dir = path.dirname(dir);
-  }
-  return path.absolute(dir);
-}
-
-/// The path to use for the package root for subprocesses.
-String get _packageRoot {
-  var sdkVersionPath = path.join(_dartdocDir, '..', '..', '..', 'version');
-  if (new File(sdkVersionPath).existsSync()) {
-    // It looks like dartdoc is being run from the SDK, so we should set the
-    // package root to the SDK's packages directory.
-    return path.absolute(path.join(_dartdocDir, '..', '..', '..', 'packages'));
-  }
-
-  // It looks like Dartdoc is being run from the Dart repo, so the package root
-  // is in the build output directory. We can find that directory relative to
-  // the Dart executable, but that could be in one of two places: in
-  // "$BUILD/dart" or "$BUILD/dart-sdk/bin/dart".
-  var executableDir = path.dirname(Platform.executable);
-  if (new Directory(path.join(executableDir, 'dart-sdk')).existsSync()) {
-    // The executable is in "$BUILD/dart".
-    return path.absolute(path.join(executableDir, 'packages'));
-  } else {
-    // The executable is in "$BUILD/dart-sdk/bin/dart".
-    return path.absolute(path.join(executableDir, '..', '..', 'packages'));
-  }
-}
-
-/// Runs dartdoc with the libraryPaths provided, and completes to dartdoc's
-/// ProcessResult.
-Future<ProcessResult> _runDartdoc(List<String> libraryPaths) {
-  var dartBin = Platform.executable;
-
-  var dartdoc = path.join(_dartdocDir, 'bin/dartdoc.dart');
-
-  final runArgs = ['--package-root=$_packageRoot/', dartdoc];
-
-  // Turn relative libraryPaths to absolute ones.
-  runArgs.addAll(libraryPaths
-      .map((e) => path.join(path.absolute(dd.scriptDir), e)));
-
-  return Process.run(dartBin, runArgs);
-}
-
-final _dartdocCompletionRegExp =
-  new RegExp(r'Documentation complete -- documented (\d+) libraries, (\d+) types, and (\d+) members\.');
-
-void _expectDocumented(String output, { int libCount, int typeCount,
-  int memberCount}) {
-
-  final completionMatches = _dartdocCompletionRegExp.allMatches(output)
-      .toList();
-
-  expect(completionMatches, hasLength(1),
-      reason: 'dartdoc output should contain one summary');
-
-  final completionMatch = completionMatches.single;
-
-  if(libCount != null) {
-    expect(int.parse(completionMatch[1]), libCount,
-        reason: 'expected library count');
-  }
-
-  if(typeCount != null) {
-    expect(int.parse(completionMatch[2]), typeCount,
-        reason: 'expected type count');
-  }
-
-  if(memberCount != null) {
-    expect(int.parse(completionMatch[3]), memberCount,
-        reason: 'expected member count');
-  }
-}
-
-
-validateDartdocMarkdown(String description, String markdown,
-    String html) {
-  var dartdoc = new dd.Dartdoc();
-  validate(description, markdown, html, linkResolver: dartdoc.dartdocResolver,
-      inlineSyntaxes: dartdoc.dartdocSyntaxes);
-}
diff --git a/sdk/lib/_internal/dartdoc/test/export_map_test.dart b/sdk/lib/_internal/dartdoc/test/export_map_test.dart
deleted file mode 100644
index 12aa98a..0000000
--- a/sdk/lib/_internal/dartdoc/test/export_map_test.dart
+++ /dev/null
@@ -1,467 +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.
-
-import 'package:unittest/unittest.dart';
-
-import 'dart:async' show Future;
-import 'dart:io' show Platform;
-
-import '../lib/src/export_map.dart';
-import '../../../../../tests/compiler/dart2js/memory_source_file_helper.dart'
-       show MemorySourceFileProvider;
-import '../../compiler/implementation/mirrors/mirrors.dart'
-       show MirrorSystem, LibraryMirror;
-import '../../compiler/implementation/mirrors/dart2js_mirror.dart'
-       as source_mirrors;
-
-Future<MirrorSystem> mirrorSystemFor(Map<String, String> memorySourceFiles) {
-  var provider = new MemorySourceFileProvider(memorySourceFiles);
-  handler(Uri uri, int begin, int end, String message, kind) {}
-
-  var script = Uri.base.resolveUri(Platform.script);
-  var libraryRoot = script.resolve('../../../../');
-  // Read packages from 'memory:packages/'.
-  var packageRoot = Uri.parse('memory:packages/');
-
-  var libraries = <Uri>[];
-  memorySourceFiles.forEach((String path, _) {
-    if (path.startsWith('packages/')) {
-      // Analyze files from 'packages/' as packages.
-      libraries.add(new Uri(scheme: 'package', path: path.substring(9)));
-    } else {
-      libraries.add(new Uri(scheme: 'memory', path: path));
-    }
-  });
-  libraries.add(new Uri(scheme: 'dart', path: 'async'));
-  return source_mirrors.analyze(
-      libraries, libraryRoot, packageRoot, provider, handler);
-}
-
-Future<ExportMap> testExports(Map<String, String> sourceFiles) {
-  return mirrorSystemFor(sourceFiles).then((mirrors) {
-    libMirror = (uri) => mirrors.libraries[Uri.parse(uri)];
-    return new ExportMap(mirrors);
-  });
-}
-
-Function libMirror;
-
-main() {
-  group('ExportMap', () {
-    test('with an empty library', () {
-      return testExports({'lib.dart': ''}).then((map) {
-        var lib = libMirror('memory:lib.dart');
-        var nonexistent = libMirror('memory:nonexistent.dart');
-
-        var expectedExports = {};
-        expectedExports[lib] = [];
-        expect(map.exports, equals(expectedExports));
-        expect(map.transitiveExports(lib), isEmpty);
-        expect(map.transitiveExports(nonexistent), isEmpty);
-      });
-    });
-
-    test('with one library with one export', () {
-      return testExports({
-        'a.dart': 'export "b.dart";',
-        'b.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b)
-        ]));
-
-        expect(map.transitiveExports(a), unorderedEquals([
-          new Export(a, b)
-        ]));
-
-        expect(map.exports[b], isEmpty);
-
-        expect(map.transitiveExports(b), isEmpty);
-      });
-    });
-
-    test('with one library with multiple exports', () {
-      return testExports({
-        'a.dart': 'export "b.dart";\nexport "c.dart";',
-        'b.dart': '', 'c.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-        var c = libMirror('memory:c.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b),
-          new Export(a, c)
-        ]));
-
-        expect(map.transitiveExports(a), unorderedEquals([
-          new Export(a, b),
-          new Export(a, c)
-        ]));
-
-        expect(map.exports[b], isEmpty);
-        expect(map.transitiveExports(b), isEmpty);
-        expect(map.exports[c], isEmpty);
-        expect(map.transitiveExports(c), isEmpty);
-      });
-    });
-
-    test('with two libraries each with one export', () {
-      return testExports({
-        'a.dart': 'export "a_export.dart";',
-        'b.dart': 'export "b_export.dart";',
-        'a_export.dart': '',
-        'b_export.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-        var a_export = libMirror('memory:a_export.dart');
-        var b_export = libMirror('memory:b_export.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, a_export),
-        ]));
-        expect(map.transitiveExports(a), unorderedEquals([
-          new Export(a, a_export),
-        ]));
-
-        expect(map.transitiveExports(b), unorderedEquals([
-          new Export(b, b_export),
-        ]));
-        expect(map.exports[b], unorderedEquals([
-          new Export(b, b_export)
-        ]));
-
-        expect(map.exports[a_export], isEmpty);
-        expect(map.transitiveExports(a_export), isEmpty);
-        expect(map.exports[b_export], isEmpty);
-        expect(map.transitiveExports(b_export), isEmpty);
-      });
-    });
-
-    test('with a transitive export', () {
-      return testExports({
-        'a.dart': 'export "b.dart";',
-        'b.dart': 'export "c.dart";',
-        'c.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-        var c = libMirror('memory:c.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b),
-        ]));
-        expect(map.transitiveExports(a), unorderedEquals([
-          new Export(a, b),
-          new Export(a, c),
-        ]));
-
-        expect(map.exports[b], unorderedEquals([
-          new Export(b, c),
-        ]));
-        expect(map.transitiveExports(b), unorderedEquals([
-          new Export(b, c),
-        ]));
-
-        expect(map.exports[c], isEmpty);
-        expect(map.transitiveExports(c), isEmpty);
-      });
-    });
-
-    test('with an export through an import', () {
-      return testExports({
-        'a.dart': 'import "b.dart";',
-        'b.dart': 'export "c.dart";',
-        'c.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-        var c = libMirror('memory:c.dart');
-
-        expect(map.exports[b], unorderedEquals([
-          new Export(b, c),
-        ]));
-        expect(map.transitiveExports(b), unorderedEquals([
-          new Export(b, c),
-        ]));
-
-        expect(map.exports[a], isEmpty);
-        expect(map.exports[c], isEmpty);
-        expect(map.transitiveExports(a), isEmpty);
-        expect(map.transitiveExports(c), isEmpty);
-      });
-    });
-
-    test('with an export with a show combinator', () {
-      return testExports({
-        'a.dart': 'export "b.dart" show x, y;',
-        'b.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b, show: ['x', 'y'])
-        ]));
-      });
-    });
-
-    test('with an export with a hide combinator', () {
-      return testExports({
-        'a.dart': 'export "b.dart" hide x, y;',
-        'b.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b, hide: ['x', 'y'])
-        ]));
-      });
-    });
-
-    test('with an export with a show and a hide combinator', () {
-      return testExports({
-        'a.dart': 'export "b.dart" show x, y hide y, z;',
-        'b.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b, show: ['x'])
-        ]));
-      });
-    });
-
-    test('composes transitive exports', () {
-      return testExports({
-        'a.dart': 'export "b.dart" hide x;',
-        'b.dart': 'export "c.dart" hide y;',
-        'c.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-        var c = libMirror('memory:c.dart');
-
-        expect(map.transitiveExports(a), unorderedEquals([
-          new Export(a, b, hide: ['x']),
-          new Export(a, c, hide: ['x', 'y'])
-        ]));
-      });
-    });
-
-    test('merges adjacent exports', () {
-      return testExports({
-        'a.dart': '''
-            export "b.dart" show x, y;
-            export "b.dart" hide y, z;
-        ''',
-        'b.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b, hide: ['z']),
-        ]));
-        expect(map.transitiveExports(a), unorderedEquals([
-          new Export(a, b, hide: ['z']),
-        ]));
-      });
-    });
-
-    test('merges adjacent exports transitively', () {
-      return testExports({
-        'a.dart': 'export "b.dart";\nexport "c.dart";',
-        'b.dart': 'export "d.dart" show x, y;',
-        'c.dart': 'export "d.dart" hide y, z;',
-        'd.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('memory:b.dart');
-        var c = libMirror('memory:c.dart');
-        var d = libMirror('memory:d.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b),
-          new Export(a, c),
-        ]));
-        expect(map.transitiveExports(a), unorderedEquals([
-          new Export(a, b),
-          new Export(a, c),
-          new Export(a, d, hide: ['z']),
-        ]));
-      });
-    });
-
-    test('resolves package: exports', () {
-      return testExports({
-        'a.dart': 'export "package:b/b.dart";',
-        'packages/b/b.dart': ''
-      }).then((map) {
-        var a = libMirror('memory:a.dart');
-        var b = libMirror('package:b/b.dart');
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b)
-        ]));
-      });
-    });
-
-    test('ignores dart: exports', () {
-      return testExports({'a.dart': 'export "dart:async";'}).then((map) {
-        var a = libMirror('memory:a.dart');
-
-        expect(map.exports[a], isEmpty);
-      });
-    });
-
-    test('.parse() resolves package: imports', () {
-      return testExports({
-        'packages/a/a.dart': 'export "package:b/b.dart";',
-        'packages/b/b.dart': ''
-      }).then((map) {
-        var a = libMirror('package:a/a.dart');
-        var b = libMirror('package:b/b.dart');
-
-        expect(map.exports[a], unorderedEquals([
-          new Export(a, b)
-        ]));
-      });
-    });
-
-    test('.parse() ignores dart: imports', () {
-      return testExports({}).then((map) {
-        expect(map.exports, isEmpty);
-      });
-    });
-  });
-
-  group('Export', () {
-    test('normalizes hide and show', () {
-      expect(new Export(null, null, show: ['x', 'y'], hide: ['y', 'z']),
-          equals(new Export(null, null, show: ['x'])));
-    });
-
-    test("doesn't care about the order of show or hide", () {
-      expect(new Export(null, null, show: ['x', 'y']),
-          equals(new Export(null, null, show: ['y', 'x'])));
-      expect(new Export(null, null, hide: ['x', 'y']),
-          equals(new Export(null, null, hide: ['y', 'x'])));
-    });
-
-    test('with no combinators considers anything visible', () {
-      var export = new Export(null, null);
-      expect(export.isMemberVisible('x'), isTrue);
-      expect(export.isMemberVisible('y'), isTrue);
-      expect(export.isMemberVisible('z'), isTrue);
-    });
-
-    test('with hide combinators considers anything not hidden visible', () {
-      var export = new Export(null, null, hide: ['x', 'y']);
-      expect(export.isMemberVisible('x'), isFalse);
-      expect(export.isMemberVisible('y'), isFalse);
-      expect(export.isMemberVisible('z'), isTrue);
-    });
-
-    test('with show combinators considers anything not shown invisible', () {
-      var export = new Export(null, null, show: ['x', 'y']);
-      expect(export.isMemberVisible('x'), isTrue);
-      expect(export.isMemberVisible('y'), isTrue);
-      expect(export.isMemberVisible('z'), isFalse);
-    });
-
-    test('composing uses the parent exporter and child path', () {
-      return testExports({
-        'exporter1.dart': '',
-        'exporter2.dart': '',
-        'path1.dart': '',
-        'path2.dart': ''
-      }).then((map) {
-        var exporter1 = libMirror('memory:exporter1.dart');
-        var exporter2 = libMirror('memory:exporter2.dart');
-        var path1 = libMirror('memory:path1.dart');
-        var path2 = libMirror('memory:path2.dart');
-        expect(new Export(exporter1, path1)
-                .compose(new Export(exporter2, path2)),
-            equals(new Export(exporter1, path2)));
-      });
-    });
-
-    test('composing show . show takes the intersection', () {
-      expect(new Export(null, null, show: ['x', 'y'])
-              .compose(new Export(null, null, show: ['y', 'z'])),
-          equals(new Export(null, null, show: ['y'])));
-    });
-
-    test('composing show . hide takes the difference', () {
-      expect(new Export(null, null, show: ['x', 'y'])
-              .compose(new Export(null, null, hide: ['y', 'z'])),
-          equals(new Export(null, null, show: ['x'])));
-    });
-
-    test('composing hide . show takes the reverse difference', () {
-      expect(new Export(null, null, hide: ['x', 'y'])
-              .compose(new Export(null, null, show: ['y', 'z'])),
-          equals(new Export(null, null, show: ['z'])));
-    });
-
-    test('composing hide . hide takes the union', () {
-      expect(new Export(null, null, hide: ['x', 'y'])
-              .compose(new Export(null, null, hide: ['y', 'z'])),
-          equals(new Export(null, null, hide: ['x', 'y', 'z'])));
-    });
-
-    test('merging requires identical exporters and paths', () {
-      return testExports({
-        'exporter1.dart': '',
-        'exporter2.dart': '',
-        'path1.dart': '',
-        'path2.dart': ''
-      }).then((map) {
-          var exporter1 = libMirror('memory:exporter1.dart');
-          var exporter2 = libMirror('memory:exporter2.dart');
-          var path1 = libMirror('memory:path1.dart');
-          var path2 = libMirror('memory:path2.dart');
-        expect(() => new Export(exporter1, null)
-                .merge(new Export(exporter2, null)),
-            throwsA(isArgumentError));
-        expect(() => new Export(null, path1)
-                .merge(new Export(null, path2)),
-            throwsA(isArgumentError));
-        expect(new Export(null, null)
-                    .merge(new Export(null, null)),
-            equals(new Export(null, null)));
-      });
-    });
-
-    test('merging show + show takes the union', () {
-      expect(new Export(null, null, show: ['x', 'y'])
-              .merge(new Export(null, null, show: ['y', 'z'])),
-          equals(new Export(null, null, show: ['x', 'y', 'z'])));
-    });
-
-    test('merging show + hide takes the difference', () {
-      expect(new Export(null, null, show: ['x', 'y'])
-              .merge(new Export(null, null, hide: ['y', 'z'])),
-          equals(new Export(null, null, hide: ['z'])));
-    });
-
-    test('merging hide + show takes the difference', () {
-      expect(new Export(null, null, hide: ['x', 'y'])
-              .merge(new Export(null, null, show: ['y', 'z'])),
-          equals(new Export(null, null, hide: ['x'])));
-    });
-
-    test('merging hide + hide takes the intersection', () {
-      expect(new Export(null, null, hide: ['x', 'y'])
-              .merge(new Export(null, null, hide: ['y', 'z'])),
-          equals(new Export(null, null, hide: ['y'])));
-    });
-  });
-}
diff --git a/sdk/lib/_internal/dartdoc/test/markdown_test.dart b/sdk/lib/_internal/dartdoc/test/markdown_test.dart
deleted file mode 100644
index aff43da..0000000
--- a/sdk/lib/_internal/dartdoc/test/markdown_test.dart
+++ /dev/null
@@ -1,912 +0,0 @@
-// Copyright (c) 2011, 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.
-
-/// Unit tests for markdown.
-library markdownTests;
-
-import 'package:unittest/unittest.dart';
-
-// TODO(rnystrom): Use "package:" URL (#4968).
-import '../lib/markdown.dart';
-
-/// Most of these tests are based on observing how showdown behaves:
-/// http://softwaremaniacs.org/playground/showdown-highlight/
-void main() {
-  group('Paragraphs', () {
-    validate('consecutive lines form a single paragraph', '''
-        This is the first line.
-        This is the second line.
-        ''', '''
-        <p>This is the first line.
-        This is the second line.</p>
-        ''');
-
-    // TODO(rnystrom): The rules here for what happens to lines following a
-    // paragraph appear to be completely arbitrary in markdown. If it makes the
-    // code significantly cleaner, we should consider ourselves free to change
-    // these tests.
-
-    validate('are terminated by a header', '''
-        para
-        # header
-        ''', '''
-        <p>para</p>
-        <h1>header</h1>
-        ''');
-
-    validate('are terminated by a setext header', '''
-        para
-        header
-        ==
-        ''', '''
-        <p>para</p>
-        <h1>header</h1>
-        ''');
-
-    validate('are terminated by a hr', '''
-        para
-        ___
-        ''', '''
-        <p>para</p>
-        <hr />
-        ''');
-
-    validate('consume an unordered list', '''
-        para
-        * list
-        ''', '''
-        <p>para
-        * list</p>
-        ''');
-
-    validate('consume an ordered list', '''
-        para
-        1. list
-        ''', '''
-        <p>para
-        1. list</p>
-        ''');
-
-    // Windows line endings have a \r\n format
-    // instead of the unix \n format.
-    validate('take account of windows line endings', '''
-        line1\r\n\r\n        line2\r\n
-        ''', '''
-        <p>line1</p>
-        <p>line2</p>
-        ''');
-  });
-
-  group('Setext headers', () {
-    validate('h1', '''
-        text
-        ===
-        ''', '''
-        <h1>text</h1>
-        ''');
-
-    validate('h2', '''
-        text
-        ---
-        ''', '''
-        <h2>text</h2>
-        ''');
-
-    validate('h1 on first line becomes text', '''
-        ===
-        ''', '''
-        <p>===</p>
-        ''');
-
-    validate('h2 on first line becomes text', '''
-        -
-        ''', '''
-        <p>-</p>
-        ''');
-
-    validate('h1 turns preceding list into text', '''
-        - list
-        ===
-        ''', '''
-        <h1>- list</h1>
-        ''');
-
-    validate('h2 turns preceding list into text', '''
-        - list
-        ===
-        ''', '''
-        <h1>- list</h1>
-        ''');
-
-    validate('h1 turns preceding blockquote into text', '''
-        > quote
-        ===
-        ''', '''
-        <h1>> quote</h1>
-        ''');
-
-    validate('h2 turns preceding blockquote into text', '''
-        > quote
-        ===
-        ''', '''
-        <h1>> quote</h1>
-        ''');
-  });
-
-  group('Headers', () {
-    validate('h1', '''
-        # header
-        ''', '''
-        <h1>header</h1>
-        ''');
-
-    validate('h2', '''
-        ## header
-        ''', '''
-        <h2>header</h2>
-        ''');
-
-    validate('h3', '''
-        ### header
-        ''', '''
-        <h3>header</h3>
-        ''');
-
-    validate('h4', '''
-        #### header
-        ''', '''
-        <h4>header</h4>
-        ''');
-
-    validate('h5', '''
-        ##### header
-        ''', '''
-        <h5>header</h5>
-        ''');
-
-    validate('h6', '''
-        ###### header
-        ''', '''
-        <h6>header</h6>
-        ''');
-
-    validate('trailing "#" are removed', '''
-        # header ######
-        ''', '''
-        <h1>header</h1>
-        ''');
-
-  });
-
-  group('Unordered lists', () {
-    validate('asterisk, plus and hyphen', '''
-        * star
-        - dash
-        + plus
-        ''', '''
-        <ul>
-          <li>star</li>
-          <li>dash</li>
-          <li>plus</li>
-        </ul>
-        ''');
-
-    validate('allow numbered lines after first', '''
-        * a
-        1. b
-        ''', '''
-        <ul>
-          <li>a</li>
-          <li>b</li>
-        </ul>
-        ''');
-
-    validate('allow a tab after the marker', '''
-        *\ta
-        +\tb
-        -\tc
-        1.\td
-        ''', '''
-        <ul>
-          <li>a</li>
-          <li>b</li>
-          <li>c</li>
-          <li>d</li>
-        </ul>
-        ''');
-
-    validate('wrap items in paragraphs if blank lines separate', '''
-        * one
-
-        * two
-        ''', '''
-        <ul>
-          <li><p>one</p></li>
-          <li><p>two</p></li>
-        </ul>
-        ''');
-
-    validate('force paragraph on item before and after blank lines', '''
-        *   one
-        *   two
-
-        *   three
-        ''', '''
-        <ul>
-          <li>one</li>
-          <li>
-            <p>two</p>
-          </li>
-          <li>
-            <p>three</p>
-          </li>
-        </ul>
-        ''');
-
-    validate('do not force paragraph if item is already block', '''
-        * > quote
-
-        * # header
-        ''', '''
-        <ul>
-          <li><blockquote><p>quote</p></blockquote></li>
-          <li><h1>header</h1></li>
-        </ul>
-        ''');
-
-    validate('can contain multiple paragraphs', '''
-        *   one
-
-            two
-
-        *   three
-        ''', '''
-        <ul>
-          <li>
-            <p>one</p>
-            <p>two</p>
-          </li>
-          <li>
-            <p>three</p>
-          </li>
-        </ul>
-        ''');
-
-    validate('can span newlines', '''
-        *   one
-            two
-        *   three
-        ''', '''
-        <ul>
-          <li>
-            <p>one
-            two</p>
-          </li>
-          <li>
-            three
-          </li>
-        </ul>
-        ''');
-
-    // TODO(rnystrom): This is how most other markdown parsers handle
-    // this but that seems like a nasty special case. For now, let's not
-    // worry about it.
-    /*
-    validate('can nest using indentation', '''
-        *   parent
-            *   child
-        ''', '''
-        <ul>
-        <li>parent
-        <ul><li>child</li></ul></li>
-        </ul>
-        ''');
-    */
-  });
-
-  group('Ordered lists', () {
-    validate('start with numbers', '''
-        1. one
-        45.  two
-           12345. three
-        ''', '''
-        <ol>
-          <li>one</li>
-          <li>two</li>
-          <li>three</li>
-        </ol>
-        ''');
-
-    validate('allow unordered lines after first', '''
-        1. a
-        * b
-        ''', '''
-        <ol>
-          <li>a</li>
-          <li>b</li>
-        </ol>
-        ''');
-  });
-
-  group('Blockquotes', () {
-    validate('single line', '''
-        > blah
-        ''', '''
-        <blockquote>
-          <p>blah</p>
-        </blockquote>
-        ''');
-
-    validate('with two paragraphs', '''
-        > first
-        >
-        > second
-        ''', '''
-        <blockquote>
-          <p>first</p>
-          <p>second</p>
-        </blockquote>
-        ''');
-
-    validate('nested', '''
-        > one
-        >> two
-        > > > three
-        ''', '''
-        <blockquote>
-          <p>one</p>
-          <blockquote>
-            <p>two</p>
-            <blockquote>
-              <p>three</p>
-            </blockquote>
-          </blockquote>
-        </blockquote>
-        ''');
-  });
-
-  group('Code blocks', () {
-    validate('single line', '''
-            code
-        ''', '''
-        <pre><code>code</code></pre>
-        ''');
-
-    validate('include leading whitespace after indentation', '''
-            zero
-             one
-              two
-               three
-        ''', '''
-        <pre><code>zero
-         one
-          two
-           three</code></pre>
-        ''');
-
-    validate('code blocks separated by newlines form one block', '''
-            zero
-            one
-
-            two
-
-            three
-        ''', '''
-        <pre><code>zero
-         one
-
-         two
-
-         three</code></pre>
-        ''');
-
-    validate('code blocks separated by two newlines form multiple blocks', '''
-            zero
-            one
-
-
-            two
-
-
-            three
-        ''', '''
-        <pre><code>zero
-         one</code></pre>
-        <pre><code>two</code></pre>
-        <pre><code>three</code></pre>
-        ''');
-
-    validate('escape HTML characters', '''
-            <&>
-        ''', '''
-        <pre><code>&lt;&amp;&gt;</code></pre>
-        ''');
-  });
-
-  group('Horizontal rules', () {
-    validate('from dashes', '''
-        ---
-        ''', '''
-        <hr />
-        ''');
-
-    validate('from asterisks', '''
-        ***
-        ''', '''
-        <hr />
-        ''');
-
-    validate('from underscores', '''
-        ___
-        ''', '''
-        <hr />
-        ''');
-
-    validate('can include up to two spaces', '''
-        _ _  _
-        ''', '''
-        <hr />
-        ''');
-  });
-
-  group('Block-level HTML', () {
-    validate('single line', '''
-        <table></table>
-        ''', '''
-        <table></table>
-        ''');
-
-    validate('multi-line', '''
-        <table>
-            blah
-        </table>
-        ''', '''
-        <table>
-            blah
-        </table>
-        ''');
-
-    validate('blank line ends block', '''
-        <table>
-            blah
-        </table>
-
-        para
-        ''', '''
-        <table>
-            blah
-        </table>
-        <p>para</p>
-        ''');
-
-    validate('HTML can be bogus', '''
-        <bogus>
-        blah
-        </weird>
-
-        para
-        ''', '''
-        <bogus>
-        blah
-        </weird>
-        <p>para</p>
-        ''');
-  });
-
-  group('Strong', () {
-    validate('using asterisks', '''
-        before **strong** after
-        ''', '''
-        <p>before <strong>strong</strong> after</p>
-        ''');
-
-    validate('using underscores', '''
-        before __strong__ after
-        ''', '''
-        <p>before <strong>strong</strong> after</p>
-        ''');
-
-    validate('unmatched asterisks', '''
-        before ** after
-        ''', '''
-        <p>before ** after</p>
-        ''');
-
-    validate('unmatched underscores', '''
-        before __ after
-        ''', '''
-        <p>before __ after</p>
-        ''');
-
-    validate('multiple spans in one text', '''
-        a **one** b __two__ c
-        ''', '''
-        <p>a <strong>one</strong> b <strong>two</strong> c</p>
-        ''');
-
-    validate('multi-line', '''
-        before **first
-        second** after
-        ''', '''
-        <p>before <strong>first
-        second</strong> after</p>
-        ''');
-  });
-
-  group('Emphasis and strong', () {
-    validate('single asterisks', '''
-        before *em* after
-        ''', '''
-        <p>before <em>em</em> after</p>
-        ''');
-
-    validate('single underscores', '''
-        before _em_ after
-        ''', '''
-        <p>before <em>em</em> after</p>
-        ''');
-
-    validate('double asterisks', '''
-        before **strong** after
-        ''', '''
-        <p>before <strong>strong</strong> after</p>
-        ''');
-
-    validate('double underscores', '''
-        before __strong__ after
-        ''', '''
-        <p>before <strong>strong</strong> after</p>
-        ''');
-
-    validate('unmatched asterisk', '''
-        before *after
-        ''', '''
-        <p>before *after</p>
-        ''');
-
-    validate('unmatched underscore', '''
-        before _after
-        ''', '''
-        <p>before _after</p>
-        ''');
-
-    validate('multiple spans in one text', '''
-        a *one* b _two_ c
-        ''', '''
-        <p>a <em>one</em> b <em>two</em> c</p>
-        ''');
-
-    validate('multi-line', '''
-        before *first
-        second* after
-        ''', '''
-        <p>before <em>first
-        second</em> after</p>
-        ''');
-
-    validate('not processed when surrounded by spaces', '''
-        a * b * c _ d _ e
-        ''', '''
-        <p>a * b * c _ d _ e</p>
-        ''');
-
-    validate('strong then emphasis', '''
-        **strong***em*
-        ''', '''
-        <p><strong>strong</strong><em>em</em></p>
-        ''');
-
-    validate('emphasis then strong', '''
-        *em***strong**
-        ''', '''
-        <p><em>em</em><strong>strong</strong></p>
-        ''');
-
-    validate('emphasis inside strong', '''
-        **strong *em***
-        ''', '''
-        <p><strong>strong <em>em</em></strong></p>
-        ''');
-
-    validate('mismatched in nested', '''
-        *a _b* c_
-        ''', '''
-        <p><em>a _b</em> c_</p>
-        ''');
-
-    validate('cannot nest tags of same type', '''
-        *a _b *c* d_ e*
-        ''', '''
-        <p><em>a _b </em>c<em> d_ e</em></p>
-        ''');
-  });
-
-  group('Inline code', () {
-    validate('simple case', '''
-        before `source` after
-        ''', '''
-        <p>before <code>source</code> after</p>
-        ''');
-
-    validate('unmatched backtick', '''
-        before ` after
-        ''', '''
-        <p>before ` after</p>
-        ''');
-    validate('multiple spans in one text', '''
-        a `one` b `two` c
-        ''', '''
-        <p>a <code>one</code> b <code>two</code> c</p>
-        ''');
-
-    validate('multi-line', '''
-        before `first
-        second` after
-        ''', '''
-        <p>before <code>first
-        second</code> after</p>
-        ''');
-
-    validate('simple double backticks', '''
-        before ``source`` after
-        ''', '''
-        <p>before <code>source</code> after</p>
-        ''');
-
-    validate('double backticks', '''
-        before ``can `contain` backticks`` after
-        ''', '''
-        <p>before <code>can `contain` backticks</code> after</p>
-        ''');
-
-    validate('double backticks with spaces', '''
-        before `` `tick` `` after
-        ''', '''
-        <p>before <code>`tick`</code> after</p>
-        ''');
-
-    validate('multiline double backticks with spaces', '''
-        before ``in `tick`
-        another`` after
-        ''', '''
-        <p>before <code>in `tick`
-        another</code> after</p>
-        ''');
-
-    validate('ignore markup inside code', '''
-        before `*b* _c_` after
-        ''', '''
-        <p>before <code>*b* _c_</code> after</p>
-        ''');
-
-    validate('escape HTML characters', '''
-        `<&>`
-        ''', '''
-        <p><code>&lt;&amp;&gt;</code></p>
-        ''');
-
-    validate('escape HTML tags', '''
-        '*' `<em>`
-        ''', '''
-        <p>'*' <code>&lt;em&gt;</code></p>
-        ''');
-  });
-
-  group('HTML encoding', () {
-    validate('less than and ampersand are escaped', '''
-        < &
-        ''', '''
-        <p>&lt; &amp;</p>
-        ''');
-    validate('greater than is not escaped', '''
-        not you >
-        ''', '''
-        <p>not you ></p>
-        ''');
-    validate('existing entities are untouched', '''
-        &amp;
-        ''', '''
-        <p>&amp;</p>
-        ''');
-  });
-
-  group('Autolinks', () {
-    validate('basic link', '''
-        before <http://foo.com/> after
-        ''', '''
-        <p>before <a href="http://foo.com/">http://foo.com/</a> after</p>
-        ''');
-    validate('handles ampersand in url', '''
-        <http://foo.com/?a=1&b=2>
-        ''', '''
-        <p><a href="http://foo.com/?a=1&b=2">http://foo.com/?a=1&amp;b=2</a></p>
-        ''');
-  });
-
-  group('Reference links', () {
-    validate('double quotes for title', '''
-        links [are] [a] awesome
-
-        [a]: http://foo.com "woo"
-        ''', '''
-        <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
-        ''');
-    validate('single quoted title', """
-        links [are] [a] awesome
-
-        [a]: http://foo.com 'woo'
-        """, '''
-        <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
-        ''');
-    validate('parentheses for title', '''
-        links [are] [a] awesome
-
-        [a]: http://foo.com (woo)
-        ''', '''
-        <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
-        ''');
-    validate('no title', '''
-        links [are] [a] awesome
-
-        [a]: http://foo.com
-        ''', '''
-        <p>links <a href="http://foo.com">are</a> awesome</p>
-        ''');
-    validate('unknown link becomes plaintext', '''
-        [not] [known]
-        ''', '''
-        <p>[not] [known]</p>
-        ''');
-    validate('can style link contents', '''
-        links [*are*] [a] awesome
-
-        [a]: http://foo.com
-        ''', '''
-        <p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
-        ''');
-    validate('inline styles after a bad link are processed', '''
-        [bad] `code`
-        ''', '''
-        <p>[bad] <code>code</code></p>
-        ''');
-    validate('empty reference uses text from link', '''
-        links [are][] awesome
-
-        [are]: http://foo.com
-        ''', '''
-        <p>links <a href="http://foo.com">are</a> awesome</p>
-        ''');
-    validate('references are case-insensitive', '''
-        links [ARE][] awesome
-
-        [are]: http://foo.com
-        ''', '''
-        <p>links <a href="http://foo.com">ARE</a> awesome</p>
-        ''');
-  });
-
-  group('Inline links', () {
-    validate('double quotes for title', '''
-        links [are](http://foo.com "woo") awesome
-        ''', '''
-        <p>links <a href="http://foo.com" title="woo">are</a> awesome</p>
-        ''');
-    validate('no title', '''
-        links [are] (http://foo.com) awesome
-        ''', '''
-        <p>links <a href="http://foo.com">are</a> awesome</p>
-        ''');
-    validate('can style link contents', '''
-        links [*are*](http://foo.com) awesome
-        ''', '''
-        <p>links <a href="http://foo.com"><em>are</em></a> awesome</p>
-        ''');
-  });
-
-  group('Resolver', () {
-    var nyanResolver = (text) => new Text('~=[,,_${text}_,,]:3');
-    validate('simple resolver', '''
-        resolve [this] thing
-        ''', '''
-        <p>resolve ~=[,,_this_,,]:3 thing</p>
-        ''', linkResolver: nyanResolver);
-  });
-
-  group('Custom inline syntax', () {
-    List<InlineSyntax> nyanSyntax =
-      [new TextSyntax('nyan', sub: '~=[,,_,,]:3')];
-    validate('simple inline syntax', '''
-        nyan
-        ''', '''
-        <p>~=[,,_,,]:3</p>
-        ''', inlineSyntaxes: nyanSyntax);
-
-    // TODO(amouravski): need more tests here for custom syntaxes, as some
-    // things are not quite working properly. The regexps are sometime a little
-    // too greedy, I think.
-  });
-}
-
-/**
- * Removes eight spaces of leading indentation from a multiline string.
- *
- * Note that this is very sensitive to how the literals are styled. They should
- * be:
- *     '''
- *     Text starts on own line. Lines up with subsequent lines.
- *     Lines are indented exactly 8 characters from the left margin.'''
- *
- * This does nothing if text is only a single line.
- */
-// TODO(nweiz): Make this auto-detect the indentation level from the first
-// non-whitespace line.
-String cleanUpLiteral(String text) {
-  var lines = text.split('\n');
-  if (lines.length <= 1) return text;
-
-  for (var j = 0; j < lines.length; j++) {
-    if (lines[j].length > 8) {
-      lines[j] = lines[j].substring(8, lines[j].length);
-    } else {
-      lines[j] = '';
-    }
-  }
-
-  return lines.join('\n');
-}
-
-validate(String description, String markdown, String html,
-         {bool verbose: false, inlineSyntaxes, linkResolver}) {
-  test(description, () {
-    markdown = cleanUpLiteral(markdown);
-    html = cleanUpLiteral(html);
-
-    var result = markdownToHtml(markdown, inlineSyntaxes: inlineSyntaxes,
-        linkResolver: linkResolver);
-    var passed = compareOutput(html, result);
-
-    if (!passed) {
-      // Remove trailing newline.
-      html = html.substring(0, html.length - 1);
-
-      print('FAIL: $description');
-      print('  expect: ${html.replaceAll("\n", "\n          ")}');
-      print('  actual: ${result.replaceAll("\n", "\n          ")}');
-      print('');
-    }
-
-    expect(passed, isTrue, verbose: verbose);
-  });
-}
-
-/// Does a loose comparison of the two strings of HTML. Ignores differences in
-/// newlines and indentation.
-compareOutput(String a, String b) {
-  int i = 0;
-  int j = 0;
-
-  skipIgnored(String s, int i) {
-    // Ignore newlines.
-    while ((i < s.length) && (s[i] == '\n')) {
-      i++;
-      // Ignore indentation.
-      while ((i < s.length) && (s[i] == ' ')) i++;
-    }
-
-    return i;
-  }
-
-  while (true) {
-    i = skipIgnored(a, i);
-    j = skipIgnored(b, j);
-
-    // If one string runs out of non-ignored strings, the other must too.
-    if (i == a.length) return j == b.length;
-    if (j == b.length) return i == a.length;
-
-    if (a[i] != b[j]) return false;
-    i++;
-    j++;
-  }
-}
diff --git a/sdk/lib/_internal/dartdoc/test/test_files/lib/no_package_test_file.dart b/sdk/lib/_internal/dartdoc/test/test_files/lib/no_package_test_file.dart
deleted file mode 100644
index 99a30ba..0000000
--- a/sdk/lib/_internal/dartdoc/test/test_files/lib/no_package_test_file.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-library no_package_test;
-
-class NoPackageTestFile {
-
-}
diff --git a/sdk/lib/_internal/dartdoc/test/test_files/package_test_file.dart b/sdk/lib/_internal/dartdoc/test/test_files/package_test_file.dart
deleted file mode 100644
index de09194..0000000
--- a/sdk/lib/_internal/dartdoc/test/test_files/package_test_file.dart
+++ /dev/null
@@ -1,5 +0,0 @@
-library package_test;
-
-class PackageTestFile {
-  
-}
diff --git a/sdk/lib/_internal/dartdoc/test/utils_test.dart b/sdk/lib/_internal/dartdoc/test/utils_test.dart
deleted file mode 100644
index fae4eec..0000000
--- a/sdk/lib/_internal/dartdoc/test/utils_test.dart
+++ /dev/null
@@ -1,45 +0,0 @@
-// Copyright (c) 2012, 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.
-
-import 'package:unittest/unittest.dart';
-
-import '../lib/src/dartdoc/utils.dart';
-
-void main() {
-  group('countOccurrences', () {
-    test('empty text returns 0', () {
-      expect(countOccurrences('', 'needle'), equals(0));
-    });
-
-    test('one occurrence', () {
-      expect(countOccurrences('bananarama', 'nara'), equals(1));
-    });
-
-    test('multiple occurrences', () {
-      expect(countOccurrences('bananarama', 'a'), equals(5));
-    });
-
-    test('overlapping matches do not count', () {
-      expect(countOccurrences('bananarama', 'ana'), equals(1));
-    });
-  });
-
-  group('repeat', () {
-    test('zero times returns an empty string', () {
-      expect(repeat('ba', 0), isEmpty);
-    });
-
-    test('one time returns the string', () {
-      expect(repeat('ba', 1), equals('ba'));
-    });
-
-    test('multiple times', () {
-      expect(repeat('ba', 3), equals('bababa'));
-    });
-
-    test('multiple times with a separator', () {
-      expect(repeat('ba', 3, separator: ' '), equals('ba ba ba'));
-    });
-  });
-}
diff --git a/sdk/lib/_internal/lib/constant_map.dart b/sdk/lib/_internal/lib/constant_map.dart
index 398d37c..7dbedbc 100644
--- a/sdk/lib/_internal/lib/constant_map.dart
+++ b/sdk/lib/_internal/lib/constant_map.dart
@@ -5,6 +5,8 @@
 part of _js_helper;
 
 abstract class ConstantMap<K, V> implements Map<K, V> {
+  const ConstantMap._();
+
   bool get isEmpty => length == 0;
 
   bool get isNotEmpty => !isEmpty;
@@ -21,10 +23,13 @@
   void addAll(Map<K, V> other) => _throwUnmodifiable();
 }
 
-// This class has no constructor. This is on purpose since the instantiation
-// is shortcut by the compiler.
 class ConstantStringMap<K, V> extends ConstantMap<K, V>
                               implements _symbol_dev.EfficientLength {
+
+  // This constructor is not used.  The instantiation is shortcut by the
+  // compiler. It is here to make the uninitialized final fields legal.
+  const ConstantStringMap._(this.length, this._jsObject, _keys) : super._();
+
   final int length;
   // A constant map is backed by a JavaScript object.
   final _jsObject;
@@ -62,6 +67,10 @@
 // This class has no constructor. This is on purpose since the instantiation
 // is shortcut by the compiler.
 class ConstantProtoMap<K, V> extends ConstantStringMap<K, V> {
+  // This constructor is not used.  The instantiation is shortcut by the
+  // compiler. It is here to make the uninitialized final fields legal.
+  ConstantProtoMap._(length, jsObject, keys) : super._(length, jsObject, keys);
+
   final V _protoValue;
 
   bool containsKey(Object key) {
@@ -82,9 +91,11 @@
   Iterator<K> get iterator => _map._keys.iterator;
 }
 
-// This class has no constructor. This is on purpose since the instantiation
-// is shortcut by the compiler.
 class GeneralConstantMap<K, V> extends ConstantMap<K, V> {
+  // This constructor is not used.  The instantiation is shortcut by the
+  // compiler. It is here to make the uninitialized final fields legal.
+  GeneralConstantMap(this._jsData) : super._();
+
   // [_jsData] holds a key-value pair list.
   final _jsData;
 
diff --git a/sdk/lib/_internal/lib/convert_patch.dart b/sdk/lib/_internal/lib/convert_patch.dart
index 1f0b0575..70b4d5f 100644
--- a/sdk/lib/_internal/lib/convert_patch.dart
+++ b/sdk/lib/_internal/lib/convert_patch.dart
@@ -92,3 +92,8 @@
 
   return revive(null, walk(json));
 }
+
+patch class _Utf8Encoder {
+  // Use Uint8List when supported on all platforms.
+  patch static List<int> _createBuffer(int size) => new List<int>(size);
+}
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index 88e4f86..a07fe16 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -41,7 +41,7 @@
 }
 
 patch class FileStat {
-  patch static List<int> _statSync(String path) {
+  patch static _statSync(String path) {
     throw new UnsupportedError("FileStat.stat");
   }
 }
diff --git a/sdk/lib/_internal/lib/isolate_helper.dart b/sdk/lib/_internal/lib/isolate_helper.dart
index 6debde7..0520864 100644
--- a/sdk/lib/_internal/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/lib/isolate_helper.dart
@@ -11,7 +11,8 @@
     Closure,
     Null,
     Primitives,
-    convertDartClosureToJS;
+    convertDartClosureToJS,
+    random64;
 import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
                                    JS,
                                    JS_CREATE_ISOLATE,
@@ -921,6 +922,13 @@
     throw "Illegal underlying port $x";
   }
 
+  visitCapability(Capability x) {
+    if (x is CapabilityImpl) {
+      return ['capability', x._id];
+    }
+    throw "Capability not serializable: $x";
+  }
+
   visitNativeJsSendPort(_NativeJsSendPort port) {
     return ['sendport', _globalState.currentManagerId,
         port._isolateId, port._receivePort._id];
@@ -942,6 +950,13 @@
     throw "Illegal underlying port $x";
   }
 
+  visitCapability(Capability x) {
+    if (x is CapabilityImpl) {
+      return new CapabilityImpl._internal(x._id);
+    }
+    throw "Capability not serializable: $x";
+  }
+
   SendPort visitNativeJsSendPort(_NativeJsSendPort port) {
     return new _NativeJsSendPort(port._receivePort, port._isolateId);
   }
@@ -970,6 +985,10 @@
       return new _WorkerSendPort(managerId, isolateId, receivePortId);
     }
   }
+
+  Capability deserializeCapability(List list) {
+    return new CapabilityImpl._internal(list[1]);
+  }
 }
 
 class _JsVisitedMap implements _MessageTraverserVisitedMap {
@@ -1062,10 +1081,13 @@
   }
 
   _dispatch(var x) {
+    // This code likely fails for user classes implementing
+    // SendPort and Capability because it assumes the internal classes.
     if (isPrimitive(x)) return visitPrimitive(x);
     if (x is List) return visitList(x);
     if (x is Map) return visitMap(x);
     if (x is SendPort) return visitSendPort(x);
+    if (x is Capability) return visitCapability(x);
 
     // Overridable fallback.
     return visitObject(x);
@@ -1075,6 +1097,7 @@
   visitList(List x);
   visitMap(Map x);
   visitSendPort(SendPort x);
+  visitCapability(Capability x);
 
   visitObject(Object x) {
     // TODO(floitsch): make this a real exception. (which one)?
@@ -1121,6 +1144,8 @@
   }
 
   visitSendPort(SendPort x) => throw new UnimplementedError();
+
+  visitCapability(Capability x) => throw new UnimplementedError();
 }
 
 /** Visitor that serializes a message as a JSON array. */
@@ -1164,6 +1189,8 @@
   }
 
   visitSendPort(SendPort x) => throw new UnimplementedError();
+
+  visitCapability(Capability x) => throw new UnimplementedError();
 }
 
 /** Deserializes arrays created with [_Serializer]. */
@@ -1191,6 +1218,7 @@
       case 'list': return _deserializeList(x);
       case 'map': return _deserializeMap(x);
       case 'sendport': return deserializeSendPort(x);
+      case 'capability': return deserializeCapability(x);
       default: return deserializeObject(x);
     }
   }
@@ -1232,6 +1260,8 @@
 
   deserializeSendPort(List x);
 
+  deserializeCapability(List x);
+
   deserializeObject(List x) {
     // TODO(floitsch): Use real exception (which one?).
     throw "Unexpected serialized object";
@@ -1319,3 +1349,41 @@
 }
 
 bool hasTimer() => JS('', '#.setTimeout', globalThis) != null;
+
+
+/**
+ * Implementation class for [Capability].
+ *
+ * It has the same name to make it harder for users to distinguish.
+ */
+class CapabilityImpl implements Capability {
+  /** Internal random secret identifying the capability. */
+  final int _id;
+
+  CapabilityImpl() : this._internal(random64());
+
+  CapabilityImpl._internal(this._id);
+
+  int get hashCode {
+    // Thomas Wang 32 bit Mix.
+    // http://www.concentric.net/~Ttwang/tech/inthash.htm
+    // (via https://gist.github.com/badboy/6267743)
+    int hash = _id;
+    hash = (hash >> 0) ^ (hash ~/ 0x100000000);  // To 32 bit from ~64.
+    hash = (~hash + (hash << 15)) & 0xFFFFFFFF;
+    hash ^= hash >> 12;
+    hash = (hash * 5) & 0xFFFFFFFF;
+    hash ^= hash >> 4;
+    hash = (hash * 2057) & 0xFFFFFFFF;
+    hash ^= hash >> 16;
+    return hash;
+  }
+
+  bool operator==(Object other) {
+    if (identical(other, this)) return true;
+    if (other is CapabilityImpl) {
+      return identical(_id, other._id);
+    }
+    return false;
+  }
+}
diff --git a/sdk/lib/_internal/lib/isolate_patch.dart b/sdk/lib/_internal/lib/isolate_patch.dart
index 45de5af..09b7955 100644
--- a/sdk/lib/_internal/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/lib/isolate_patch.dart
@@ -4,11 +4,12 @@
 
 // Patch file for the dart:isolate library.
 
-import 'dart:_isolate_helper' show IsolateNatives,
-                                   ReceivePortImpl,
-                                   RawReceivePortImpl,
+import 'dart:_isolate_helper' show CapabilityImpl,
                                    CloseToken,
-                                   JsIsolateSink;
+                                   IsolateNatives,
+                                   JsIsolateSink,
+                                   ReceivePortImpl,
+                                   RawReceivePortImpl;
 
 patch class Isolate {
   patch static Future<Isolate> spawn(void entryPoint(message), var message) {
@@ -54,3 +55,7 @@
     return new RawReceivePortImpl(handler);
   }
 }
+
+patch class Capability {
+  patch factory Capability() = CapabilityImpl;
+}
diff --git a/sdk/lib/_internal/lib/js_helper.dart b/sdk/lib/_internal/lib/js_helper.dart
index 54fb1b8..8be9ee5 100644
--- a/sdk/lib/_internal/lib/js_helper.dart
+++ b/sdk/lib/_internal/lib/js_helper.dart
@@ -407,7 +407,7 @@
               FIRST_DEFAULT_ARGUMENT, parameter, requiredParameterCount);
   }
 
-  @NoInline
+  @NoInline()
   computeFunctionRti(jsConstructor) {
     if (JS('bool', 'typeof # == "number"', functionType)) {
       return getMetadata(functionType);
@@ -2173,12 +2173,12 @@
     return receiverHashCode ^ Primitives.objectHashCode(_target);
   }
 
-  @NoInline
+  @NoInline()
   static selfOf(BoundClosure closure) => closure._self;
 
   static targetOf(BoundClosure closure) => closure._target;
 
-  @NoInline
+  @NoInline()
   static receiverOf(BoundClosure closure) => closure._receiver;
 
   static nameOf(BoundClosure closure) => closure._name;
@@ -2695,7 +2695,7 @@
 
   @NoInline() @NoSideEffects()
   _assertCheck(expression) {
-    if (inAssert) return;
+    if (inAssert) return null;
     inAssert = true; // Don't try to check this library itself.
     try {
       // Type inferrer don't think this is called with dynamic arguments.
@@ -3038,3 +3038,15 @@
 
   String toString() => "Unsupported operation: $_message";
 }
+
+/**
+ * Creates a random number with 64 bits of randomness.
+ *
+ * This will be truncated to the 53 bits available in a double.
+ */
+int random64() {
+  // TODO(lrn): Use a secure random source.
+  int int32a = JS("int", "(Math.random() * 0x100000000) >>> 0");
+  int int32b = JS("int", "(Math.random() * 0x100000000) >>> 0");
+  return int32a + int32b * 0x100000000;
+}
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index 24e7840..067b616 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -934,21 +934,26 @@
   // JS helpers for getField optimizations.
   static bool isUndefined(x)
       => JS('bool', 'typeof # == "undefined"', x);
+  static bool isMissingCache(x)
+      => JS('bool', 'typeof # == "number"', x);
   static bool isMissingProbe(Symbol symbol)
       => JS('bool', 'typeof #.\$p == "undefined"', symbol);
-  static bool isNewFunctionAllowed()
+  static bool isEvalAllowed()
       => JS('bool', 'typeof dart_precompiled != "function"');
 
 
-  /// The getter cache is specific to this [InstanceMirror]
-  /// and maps reflective names to functions that will invoke
-  /// the corresponding getter on the reflectee. The reflectee
-  /// is passed to the function as the first argument to avoid
-  /// the overhead of fetching it from this mirror repeatedly.
+  /// The getter cache is lazily allocated after a couple
+  /// of invocations of [InstanceMirror.getField]. The delay is
+  /// used to avoid too aggressive caching and dynamic function
+  /// generation for rarely used mirrors. The cache is specific to
+  /// this [InstanceMirror] and maps reflective names to functions
+  /// that will invoke the corresponding getter on the reflectee.
+  /// The reflectee is passed to the function as the first argument
+  /// to avoid the overhead of fetching it from this mirror repeatedly.
   /// The cache is lazily initialized to a JS object so we can
   /// benefit from "map transitions" in the underlying JavaScript
   /// engine to speed up cache probing.
-  var _getterCache;
+  var _getterCache = 4;
 
   InstanceMirror getField(Symbol fieldName) {
     // BUG(16400): This should be a labelled block, but that makes
@@ -956,7 +961,7 @@
     // inferencing implementation.
     do {
       var cache = _getterCache;
-      if (cache == null || isMissingProbe(fieldName)) break;
+      if (isMissingCache(cache) || isMissingProbe(fieldName)) break;
       // If the [fieldName] has an associated probe function, we can use
       // it to read from the getter cache specific to this [InstanceMirror].
       var getter = JS('', '#.\$p(#)', fieldName, cache);
@@ -985,29 +990,29 @@
     String name = n(fieldName);
     var result = _invoke(fieldName, JSInvocationMirror.GETTER, name, const []);
     var cacheEntry = JsCache.fetch(_classInvocationCache, name);
-    if (cacheEntry.isNoSuchMethod || cacheEntry.isIntercepted) {
+    if (cacheEntry.isNoSuchMethod) {
       return result;
     }
 
     // Make sure we have a getter cache in this [InstanceMirror].
     var cache = _getterCache;
-    if (cache == null) {
-      cache = _getterCache = JS('=Object', 'Object.create(null)');
+    if (isMissingCache(cache)) {
+      if ((_getterCache = --cache) != 0) return result;
+      cache = _getterCache = JS('=Object', '({})');
     }
 
     // Make sure that symbol [fieldName] has a cache probing function ($p).
+    bool useEval = isEvalAllowed();
     if (isMissingProbe(fieldName)) {
-      var probe = isNewFunctionAllowed()
-          ? JS('', 'new Function("c", "return c." + # + ";")', name)
-          : JS('', 'function (c) { return c[#]; }', name);
+      var probe = _newProbeFn(name, useEval);
       JS('void', '#.\$p = #', fieldName, probe);
     }
 
     // Create a new getter function and install it in the cache.
     var mangledName = cacheEntry.mangledName;
-    var getter = isNewFunctionAllowed()
-          ? JS('', 'new Function("o", "return o." + # + "();")', mangledName)
-          : JS('', 'function(o) { return o[#](); }', mangledName);
+    var getter = (cacheEntry.isIntercepted)
+        ? _newInterceptedGetterFn(mangledName, useEval)
+        : _newGetterFn(mangledName, useEval);
     JS('void', '#[#] = #', cache, name, getter);
 
     // Initialize the last value (v) and last mirror (m) on the
@@ -1019,6 +1024,53 @@
     return result;
   }
 
+  _newProbeFn(String id, bool useEval) {
+    if (useEval) {
+      // We give the probe function a name to make it appear nicely in
+      // profiles and when debugging. The name also makes the source code
+      // for the function more "unique" so the underlying JavaScript
+      // engine is less likely to re-use an existing piece of generated
+      // code as the result of calling eval. In return, this leads to
+      // less polymorphic access in the probe function.
+      var body = "(function probe\$$id(c){return c.$id})";
+      return JS('', '(function(b){return eval(b)})(#)', body);
+    } else {
+      return JS('', '(function(n){return(function(c){return c[n]})})(#)', id);
+    }
+  }
+
+  _newGetterFn(String name, bool useEval) {
+    if (!useEval) return _newGetterNoEvalFn(name);
+    // We give the getter function a name that associates it with the
+    // class of the reflectee. This makes it easier to spot in profiles
+    // and when debugging, but it also means that the underlying JavaScript
+    // engine will only share the generated code for accessors on the
+    // same class (through caching of eval'ed code). This makes the
+    // generated call to the getter - e.g. o.get$foo() - much more likely
+    // to be monomorphic and inlineable.
+    String className = JS('String', '#.constructor.name', reflectee);
+    var body = "(function $className\$$name(o){return o.$name()})";
+    return JS('', '(function(b){return eval(b)})(#)', body);
+  }
+
+  _newGetterNoEvalFn(n) => JS('',
+      '(function(n){return(function(o){return o[n]()})})(#)', n);
+
+  _newInterceptedGetterFn(String name, bool useEval) {
+    var object = reflectee;
+    // It is possible that the interceptor for a given object is the object
+    // itself, so it is important not to share the code that captures the
+    // interceptor between multiple different instances of [InstanceMirror].
+    var interceptor = getInterceptor(object);
+    if (!useEval) return _newInterceptGetterNoEvalFn(name, interceptor);
+    String className = JS('String', '#.constructor.name', object);
+    var body = "(function $className\$$name(o){return i.$name(o)})";
+    return JS('', '(function(b,i){return eval(b)})(#,#)', body, interceptor);
+  }
+
+  _newInterceptGetterNoEvalFn(n, i) => JS('',
+      '(function(n,i){return(function(o){return i[n](o)})})(#,#)', n, i);
+
   delegate(Invocation invocation) {
     return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
   }
diff --git a/sdk/lib/_internal/lib/math_patch.dart b/sdk/lib/_internal/lib/math_patch.dart
index e3aabe3..2ba47aa 100644
--- a/sdk/lib/_internal/lib/math_patch.dart
+++ b/sdk/lib/_internal/lib/math_patch.dart
@@ -80,23 +80,81 @@
   static const int _MASK32 = 0xFFFFFFFF;
 
   // State comprised of two unsigned 32 bit integers.
-  int _lo;
-  int _hi;
+  int _lo = 0;
+  int _hi = 0;
 
   // Implements:
+  //   uint64_t hash = 0;
   //   do {
-  //     seed = (seed + 0x5A17) & _Random._MASK_64;
-  //   } while (seed == 0);
-  //   _lo = seed & _MASK_32;
-  //   _hi = seed >> 32;
+  //      hash = hash * 1037 ^ mix64((uint64_t)seed);
+  //      seed >>= 64;
+  //   } while (seed != 0 && seed != -1);  // Limits for pos/neg seed.
+  //   if (hash == 0) {
+  //     hash = 0x5A17;
+  //   }
+  //   _lo = hash & _MASK_32;
+  //   _hi = hash >> 32;
   // and then does four _nextState calls to shuffle bits around.
   _Random(int seed) {
-    // Works the same as the VM version for positive integers up to 2^53.
-    // For bigints, the VM always uses zero as seed. That is really a bug, and
-    // we don't simulate that.
-    seed += 0x5A17;
-    _lo = seed & _MASK32;
-    _hi = (seed - _lo) ~/ _POW2_32;
+    int empty_seed = 0;
+    if (seed < 0) {
+      empty_seed = -1;
+    }
+    do {
+      int low = seed & _MASK32;
+      seed = (seed - low) ~/ _POW2_32;
+      int high = seed & _MASK32;
+      seed = (seed - high) ~/ _POW2_32;
+
+      // Thomas Wang's 64-bit mix function.
+      // http://www.concentric.net/~Ttwang/tech/inthash.htm
+      // via. http://web.archive.org/web/20071223173210/http://www.concentric.net/~Ttwang/tech/inthash.htm
+
+      // key = ~key + (key << 21);
+      int tmplow = low << 21;
+      int tmphigh = (high << 21) | (low >> 11);
+      tmplow = (~low & _MASK32) + tmplow;
+      low = tmplow & _MASK32;
+      high = (~high + tmphigh + ((tmplow - low) ~/ 0x100000000)) & _MASK32;
+      // key = key ^ (key >> 24).
+      tmphigh = high >> 24;
+      tmplow = (low >> 24) | (high << 8);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key * 265
+      tmplow = low * 265;
+      low = tmplow & _MASK32;
+      high = (high * 265 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // key = key ^ (key >> 14);
+      tmphigh = high >> 14;
+      tmplow = (low >> 14) | (high << 18);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key * 21
+      tmplow = low * 21;
+      low = tmplow & _MASK32;
+      high = (high * 21 + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // key = key ^ (key >> 28).
+      tmphigh = high >> 28;
+      tmplow = (low >> 28) | (high << 4);
+      low ^= tmplow;
+      high ^= tmphigh;
+      // key = key + (key << 31);
+      tmplow = low << 31;
+      tmphigh = (high << 31) | (low >> 1);
+      tmplow += low;
+      low = tmplow & _MASK32;
+      high = (high + tmphigh + (tmplow - low) ~/ 0x100000000) & _MASK32;
+      // Mix end.
+
+      // seed = seed * 1037 ^ key;
+      tmplow = _lo * 1037;
+      _lo = tmplow & _MASK32;
+      _hi = (_hi * 1037 + (tmplow - _lo) ~/ 0x100000000) & _MASK32;
+      _lo ^= low;
+      _hi ^= high;
+    } while (seed != empty_seed);
+
     if (_hi == 0 && _lo == 0) {
       _lo = 0x5A17;
     }
diff --git a/sdk/lib/_internal/pub/bin/pub.dart b/sdk/lib/_internal/pub/bin/pub.dart
index a589dcc..ecc8318 100644
--- a/sdk/lib/_internal/pub/bin/pub.dart
+++ b/sdk/lib/_internal/pub/bin/pub.dart
@@ -7,9 +7,11 @@
 
 import 'package:args/args.dart';
 import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
 
 import '../lib/src/command.dart';
 import '../lib/src/exit_codes.dart' as exit_codes;
+import '../lib/src/http.dart';
 import '../lib/src/io.dart';
 import '../lib/src/log.dart' as log;
 import '../lib/src/sdk.dart' as sdk;
@@ -38,18 +40,6 @@
     return;
   }
 
-  if (options.command == null) {
-    if (options.rest.isEmpty) {
-      // No command was chosen.
-      PubCommand.printGlobalUsage();
-    } else {
-      log.error('Could not find a command named "${options.rest[0]}".');
-      log.error('Run "pub help" to see available commands.');
-      flushThenExit(exit_codes.USAGE);
-    }
-    return;
-  }
-
   if (options['trace']) {
     log.recordTranscript();
   }
@@ -81,8 +71,125 @@
     cacheDir = '${Platform.environment['HOME']}/.pub-cache';
   }
 
-  validatePlatform().then((_) {
-    PubCommand.commands[options.command.name].run(cacheDir, options, arguments);
+  validatePlatform().then((_) => runPub(cacheDir, options, arguments));
+}
+
+/// Runs the appropriate pub command whose [arguments] have been parsed to
+/// [options] using the system cache in [cacheDir].
+///
+/// Handles and correctly reports any errors that occur while running.
+void runPub(String cacheDir, ArgResults options, List<String> arguments) {
+  var captureStackChains =
+      options['trace'] ||
+      options['verbose'] ||
+      options['verbosity'] == 'all';
+
+  captureErrors(() => invokeCommand(cacheDir, options),
+      captureStackChains: captureStackChains).catchError((error, Chain chain) {
+    // This is basically the top-level exception handler so that we don't
+    // spew a stack trace on our users.
+    var message;
+
+    log.error(getErrorMessage(error));
+    log.fine("Exception type: ${error.runtimeType}");
+
+    if (options['trace'] || !isUserFacingException(error)) {
+      log.error(chain.terse);
+    } else {
+      log.fine(chain.terse);
+    }
+
+    if (error is ApplicationException && error.innerError != null) {
+      var message = "Wrapped exception: ${error.innerError}";
+      if (error.innerTrace != null) message = "$message\n${error.innerTrace}";
+      log.fine(message);
+    }
+
+    if (options['trace']) {
+      log.dumpTranscript();
+    } else if (!isUserFacingException(error)) {
+      log.error("""
+This is an unexpected error. Please run
+
+    pub --trace ${arguments.map((arg) => "'$arg'").join(' ')}
+
+and include the results in a bug report on http://dartbug.com/new.
+""");
+    }
+
+    return flushThenExit(chooseExitCode(error));
+  }).then((_) {
+    // Explicitly exit on success to ensure that any dangling dart:io handles
+    // don't cause the process to never terminate.
+    return flushThenExit(exit_codes.SUCCESS);
+  });
+}
+
+/// Returns the appropriate exit code for [exception], falling back on 1 if no
+/// appropriate exit code could be found.
+int chooseExitCode(exception) {
+  if (exception is HttpException || exception is HttpException ||
+      exception is SocketException || exception is PubHttpException) {
+    return exit_codes.UNAVAILABLE;
+  } else if (exception is FormatException) {
+    return exit_codes.DATA;
+  } else if (exception is UsageException) {
+    return exit_codes.USAGE;
+  } else {
+    return 1;
+  }
+}
+
+/// Walks the command tree and runs the selected pub command.
+Future invokeCommand(String cacheDir, ArgResults mainOptions) {
+  var commands = PubCommand.mainCommands;
+  var command;
+  var commandString = "pub";
+  var options = mainOptions;
+
+  while (commands.isNotEmpty) {
+    if (options.command == null) {
+      if (options.rest.isEmpty) {
+        if (command == null) {
+          // No top-level command was chosen.
+          PubCommand.printGlobalUsage();
+          return new Future.value();
+        }
+
+        command.usageError('Missing subcommand for "$commandString".');
+      } else {
+        if (command == null) {
+          PubCommand.usageErrorWithCommands(commands,
+              'Could not find a command named "${options.rest[0]}".');
+        }
+
+        command.usageError('Could not find a subcommand named '
+            '"${options.rest[0]}" for "$commandString".');
+      }
+    }
+
+    // Step into the command.
+    options = options.command;
+    command = commands[options.name];
+    commands = command.subcommands;
+    commandString += " ${options.name}";
+
+    if (options['help']) {
+      command.printUsage();
+      return new Future.value();
+    }
+  }
+
+  // Make sure there aren't unexpected arguments.
+  if (!command.takesArguments && options.rest.isNotEmpty) {
+    command.usageError(
+        'Command "${options.name}" does not take any arguments.');
+  }
+
+  return syncFuture(() {
+    return command.run(cacheDir, options);
+  }).whenComplete(() {
+    command.cache.deleteTempDir();
   });
 }
 
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index e3dcab5..3f6f35e 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -5,12 +5,10 @@
 library pub.command;
 
 import 'dart:async';
-import 'dart:io';
 import 'dart:math' as math;
 
 import 'package:args/args.dart';
 import 'package:path/path.dart' as path;
-import 'package:stack_trace/stack_trace.dart';
 
 import 'command/build.dart';
 import 'command/cache.dart';
@@ -23,17 +21,18 @@
 import 'command/uploader.dart';
 import 'command/version.dart';
 import 'entrypoint.dart';
-import 'exit_codes.dart' as exit_codes;
-import 'http.dart';
-import 'io.dart';
 import 'log.dart' as log;
 import 'system_cache.dart';
 import 'utils.dart';
 
 /// The base class for commands for the pub executable.
+///
+/// A command may either be a "leaf" command or it may be a parent for a set
+/// of subcommands. Only leaf commands are ever actually invoked. If a command
+/// has subcommands, then one of those must always be chosen.
 abstract class PubCommand {
   /// The commands that pub understands.
-  static final Map<String, PubCommand> commands = _initCommands();
+  static final Map<String, PubCommand> mainCommands = _initCommands();
 
   /// The top-level [ArgParser] used to parse the pub command line.
   static final pubArgParser = _initArgParser();
@@ -44,35 +43,59 @@
     var buffer = new StringBuffer();
     buffer.writeln('Pub is a package manager for Dart.');
     buffer.writeln();
-    buffer.writeln('Usage: pub command [arguments]');
+    buffer.writeln('Usage: pub <command> [arguments]');
     buffer.writeln();
     buffer.writeln('Global options:');
     buffer.writeln(pubArgParser.getUsage());
+    buffer.write(_listCommands(mainCommands));
     buffer.writeln();
+    buffer.writeln(
+        'Use "pub help [command]" for more information about a command.');
 
-    // Show the public commands alphabetically.
-    var names = ordered(commands.keys.where((name) =>
-        !commands[name].aliases.contains(name) &&
-        !commands[name].hidden));
+    log.message(buffer);
+  }
 
+  /// Fails with a usage error [message] when trying to select from one of
+  /// [commands].
+  static void usageErrorWithCommands(Map<String, PubCommand> commands,
+                                String message) {
+    throw new UsageException("$message\n${_listCommands(commands)}");
+  }
+
+  /// Writes [commands] in a nicely formatted list to [buffer].
+  static String _listCommands(Map<String, PubCommand> commands) {
+    // If there are no subcommands, do nothing.
+    if (commands.isEmpty) return "";
+
+    // Don't include aliases.
+    var names = commands.keys
+        .where((name) => !commands[name].aliases.contains(name));
+
+    // Filter out hidden ones, unless they are all hidden.
+    var visible = names.where((name) => !commands[name].hidden);
+    if (visible.isNotEmpty) names = visible;
+
+    // Show the commands alphabetically.
+    names = ordered(names);
     var length = names.map((name) => name.length).reduce(math.max);
+    var isSubcommand = commands != mainCommands;
 
-    buffer.writeln('Available commands:');
+    var buffer = new StringBuffer();
+    buffer.writeln();
+    buffer.writeln('Available ${isSubcommand ? "sub" : ""}commands:');
     for (var name in names) {
       buffer.writeln('  ${padRight(name, length)}   '
           '${commands[name].description}');
     }
 
-    buffer.writeln();
-    buffer.write(
-        'Use "pub help [command]" for more information about a command.');
-    log.message(buffer.toString());
+    return buffer.toString();
   }
 
   SystemCache cache;
 
   /// The parsed options for this command.
-  ArgResults commandOptions;
+  ArgResults get commandOptions => _commandOptions;
+  ArgResults _commandOptions;
 
   Entrypoint entrypoint;
 
@@ -81,18 +104,27 @@
 
   /// If the command is undocumented and should not appear in command listings,
   /// this will be `true`.
-  bool get hidden => false;
+  bool get hidden {
+    // Leaf commands are visible by default.
+    if (subcommands.isEmpty) return false;
+
+    // Otherwise, a command is hidden if all of its subcommands are.
+    return subcommands.values.every((subcommand) => subcommand.hidden);
+  }
 
   /// How to invoke this command (e.g. `"pub get [package]"`).
   String get usage;
 
-  /// Whether or not this command requires [entrypoint] to be defined. If false,
-  /// pub won't look for a pubspec and [entrypoint] will be null when the
-  /// command runs.
+  /// Whether or not this command requires [entrypoint] to be defined.
+  ///
+  /// If false, pub won't look for a pubspec and [entrypoint] will be null when
+  /// the command runs. This only needs to be set in leaf commands.
   bool get requiresEntrypoint => true;
 
-  /// Whether or not this command takes arguments in addition to options. If
-  /// false, pub will exit with an error if arguments are provided.
+  /// Whether or not this command takes arguments in addition to options.
+  ///
+  /// If false, pub will exit with an error if arguments are provided. This
+  /// only needs to be set in leaf commands.
   bool get takesArguments => false;
 
   /// Alternate names for this command. These names won't be used in the
@@ -102,9 +134,17 @@
   /// The [ArgParser] for this command.
   final commandParser = new ArgParser();
 
+  /// Subcommands exposed by this command.
+  ///
+  /// If empty, then this command has no subcommands. Otherwise, a subcommand
+  /// must be specified by the user. In that case, this command's [onRun] will
+  /// not be called and the subcommand's will.
+  final subcommands = <String, PubCommand>{};
+
   /// Override this to use offline-only sources instead of hitting the network.
+  ///
   /// This will only be called before the [SystemCache] is created. After that,
-  /// it has no effect.
+  /// it has no effect. This only needs to be set in leaf commands.
   bool get isOffline => false;
 
   PubCommand() {
@@ -113,94 +153,50 @@
         help: 'Print usage information for this command.');
   }
 
-  void run(String cacheDir, ArgResults options, List<String> arguments) {
-    commandOptions = options.command;
-
-    if (commandOptions['help']) {
-      this.printUsage();
-      return;
-    }
+  /// Runs this command using a system cache at [cacheDir] with [options].
+  Future run(String cacheDir, ArgResults options) {
+    _commandOptions = options;
 
     cache = new SystemCache.withSources(cacheDir, isOffline: isOffline);
 
-    handleError(error, Chain chain) {
-      // This is basically the top-level exception handler so that we don't
-      // spew a stack trace on our users.
-      var message;
-
-      log.error(getErrorMessage(error));
-      log.fine("Exception type: ${error.runtimeType}");
-
-      if (options['trace'] || !isUserFacingException(error)) {
-        log.error(chain.terse);
-      } else {
-        log.fine(chain.terse);
-      }
-
-      if (error is ApplicationException && error.innerError != null) {
-        var message = "Wrapped exception: ${error.innerError}";
-        if (error.innerTrace != null) message = "$message\n${error.innerTrace}";
-        log.fine(message);
-      }
-
-      if (options['trace']) {
-        log.dumpTranscript();
-      } else if (!isUserFacingException(error)) {
-        log.error("""
-This is an unexpected error. Please run
-
-    pub --trace ${arguments.map((arg) => "'$arg'").join(' ')}
-
-and include the results in a bug report on http://dartbug.com/new.
-""");
-      }
-
-      return flushThenExit(_chooseExitCode(error));
+    if (requiresEntrypoint) {
+      // TODO(rnystrom): Will eventually need better logic to walk up
+      // subdirectories until we hit one that looks package-like. For now,
+      // just assume the cwd is it.
+      entrypoint = new Entrypoint(path.current, cache);
     }
 
-    var captureStackChains =
-        options['trace'] || options['verbose'] || options['verbosity'] == 'all';
-    captureErrors(() {
-      return syncFuture(() {
-        // Make sure there aren't unexpected arguments.
-        if (!takesArguments && commandOptions.rest.isNotEmpty) {
-          log.error('Command "${commandOptions.name}" does not take any '
-                    'arguments.');
-          this.printUsage();
-          return flushThenExit(exit_codes.USAGE);
-        }
-
-        if (requiresEntrypoint) {
-          // TODO(rnystrom): Will eventually need better logic to walk up
-          // subdirectories until we hit one that looks package-like. For now,
-          // just assume the cwd is it.
-          entrypoint = new Entrypoint(path.current, cache);
-        }
-
-        var commandFuture = onRun();
-        if (commandFuture == null) return true;
-
-        return commandFuture;
-      }).whenComplete(() => cache.deleteTempDir());
-    }, captureStackChains: captureStackChains).catchError(handleError)
-        .then((_) {
-      // Explicitly exit on success to ensure that any dangling dart:io handles
-      // don't cause the process to never terminate.
-      return flushThenExit(exit_codes.SUCCESS);
-    });
+    return syncFuture(onRun);
   }
 
-  /// Override this to perform the specific command. Return a future that
-  /// completes when the command is done or fails if the command fails. If the
-  /// command is synchronous, it may return `null`.
-  Future onRun();
+  /// Override this to perform the specific command.
+  ///
+  /// Return a future that completes when the command is done or fails if the
+  /// command fails. If the command is synchronous, it may return `null`. Only
+  /// leaf command should override this.
+  Future onRun() {
+    // Leaf commands should override this and non-leaf commands should never
+    // call it.
+    assert(false);
+  }
 
   /// Displays usage information for this command.
   void printUsage([String description]) {
     if (description == null) description = this.description;
+    log.message('$description\n\n${_getUsage()}');
+  }
 
+  // TODO(rnystrom): Use this in other places handle usage failures.
+  /// Throw an [ApplicationException] for a usage error of this command with
+  /// [message].
+  void usageError(String message) {
+    throw new UsageException("$message\n\n${_getUsage()}");
+  }
+
+  /// Generates a string of usage information for this command.
+  String _getUsage() {
     var buffer = new StringBuffer();
-    buffer.write('$description\n\nUsage: $usage');
+    buffer.write('Usage: $usage');
 
     var commandUsage = commandParser.getUsage();
     if (!commandUsage.isEmpty) {
@@ -208,20 +204,12 @@
       buffer.write(commandUsage);
     }
 
-    log.message(buffer.toString());
-  }
-
-  /// Returns the appropriate exit code for [exception], falling back on 1 if no
-  /// appropriate exit code could be found.
-  int _chooseExitCode(exception) {
-    if (exception is HttpException || exception is HttpException ||
-        exception is SocketException || exception is PubHttpException) {
-      return exit_codes.UNAVAILABLE;
-    } else if (exception is FormatException) {
-      return exit_codes.DATA;
-    } else {
-      return 1;
+    if (subcommands.isNotEmpty) {
+      buffer.writeln();
+      buffer.write(_listCommands(subcommands));
     }
+
+    return buffer.toString();
   }
 }
 
@@ -272,9 +260,19 @@
       help: 'Shortcut for "--verbosity=all".');
 
   // Register the commands.
-  PubCommand.commands.forEach((name, command) {
-    argParser.addCommand(name, command.commandParser);
+  PubCommand.mainCommands.forEach((name, command) {
+    _registerCommand(name, command, argParser);
   });
 
   return argParser;
 }
+
+/// Registers a [command] with [name] on [parser].
+void _registerCommand(String name, PubCommand command, ArgParser parser) {
+  parser.addCommand(name, command.commandParser);
+
+  // Recursively wire up any subcommands.
+  command.subcommands.forEach((name, subcommand) {
+    _registerCommand(name, subcommand, command.commandParser);
+  });
+}
diff --git a/sdk/lib/_internal/pub/lib/src/command/build.dart b/sdk/lib/_internal/pub/lib/src/command/build.dart
index b470f1b..5131ea2 100644
--- a/sdk/lib/_internal/pub/lib/src/command/build.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/build.dart
@@ -27,8 +27,7 @@
 
 /// Handles the `build` pub command.
 class BuildCommand extends PubCommand {
-  String get description =>
-      "Copy and compile all Dart entrypoints in the 'web' directory.";
+  String get description => "Apply transformers to build a package.";
   String get usage => "pub build [options]";
   List<String> get aliases => const ["deploy", "settle-up"];
   bool get takesArguments => true;
diff --git a/sdk/lib/_internal/pub/lib/src/command/cache.dart b/sdk/lib/_internal/pub/lib/src/command/cache.dart
index 97e5dbe..dbef315 100644
--- a/sdk/lib/_internal/pub/lib/src/command/cache.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/cache.dart
@@ -4,48 +4,15 @@
 
 library pub.command.cache;
 
-import 'dart:async';
-import 'dart:convert';
-
 import '../command.dart';
-import '../exit_codes.dart' as exit_codes;
-import '../io.dart';
-import '../log.dart' as log;
+import 'cache_list.dart';
 
 /// Handles the `cache` pub command.
 class CacheCommand extends PubCommand {
-  String get description => "Inspect the system cache.";
-  String get usage => "pub cache list";
-  bool get hidden => true;
-  bool get requiresEntrypoint => false;
-  bool get takesArguments => true;
+  String get description => "Work with the system cache.";
+  String get usage => "pub cache <subcommand>";
 
-  Future onRun() {
-    // TODO(rnystrom): Use subcommand for "list".
-    if (commandOptions.rest.length != 1) {
-      log.error('The cache command expects one argument.');
-      this.printUsage();
-      return flushThenExit(exit_codes.USAGE);
-    }
-
-    if ((commandOptions.rest[0] != 'list')) {
-      log.error('Unknown cache command "${commandOptions.rest[0]}".');
-      this.printUsage();
-      return flushThenExit(exit_codes.USAGE);
-    }
-
-    // TODO(keertip): Add flag to list packages from non default sources
-    var packagesObj = <String, Map>{};
-
-    for (var package in cache.sources.defaultSource.getCachedPackages()) {
-
-      var packageInfo = packagesObj.putIfAbsent(package.name, () => {});
-      packageInfo[package.version.toString()] = {'location': package.dir};
-    }
-
-    // TODO(keertip): Add support for non-JSON format
-    // and check for --format flag
-    log.message(JSON.encode({'packages': packagesObj}));
-  }
+  final subcommands = {
+    "list": new CacheListCommand()
+  };
 }
-
diff --git a/sdk/lib/_internal/pub/lib/src/command/cache_list.dart b/sdk/lib/_internal/pub/lib/src/command/cache_list.dart
new file mode 100644
index 0000000..d774a6b
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/command/cache_list.dart
@@ -0,0 +1,33 @@
+// 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.
+
+library pub.command.cache_list;
+
+import 'dart:async';
+import 'dart:convert';
+
+import '../command.dart';
+import '../log.dart' as log;
+
+/// Handles the `cache list` pub command.
+class CacheListCommand extends PubCommand {
+  String get description => "List packages in the system cache.";
+  String get usage => "pub cache list";
+  bool get hidden => true;
+  bool get requiresEntrypoint => false;
+
+  Future onRun() {
+    // TODO(keertip): Add flag to list packages from non default sources.
+    var packagesObj = <String, Map>{};
+
+    for (var package in cache.sources.defaultSource.getCachedPackages()) {
+      var packageInfo = packagesObj.putIfAbsent(package.name, () => {});
+      packageInfo[package.version.toString()] = {'location': package.dir};
+    }
+
+    // TODO(keertip): Add support for non-JSON format and check for --format
+    // flag.
+    log.message(JSON.encode({'packages': packagesObj}));
+  }
+}
diff --git a/sdk/lib/_internal/pub/lib/src/command/help.dart b/sdk/lib/_internal/pub/lib/src/command/help.dart
index 9118175..c1889ff 100644
--- a/sdk/lib/_internal/pub/lib/src/command/help.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/help.dart
@@ -7,9 +7,6 @@
 import 'dart:async';
 
 import '../command.dart';
-import '../exit_codes.dart' as exit_codes;
-import '../io.dart';
-import '../log.dart' as log;
 
 /// Handles the `help` pub command.
 class HelpCommand extends PubCommand {
@@ -19,18 +16,39 @@
   bool get takesArguments => true;
 
   Future onRun() {
+    // Show the default help if no command was specified.
     if (commandOptions.rest.isEmpty) {
       PubCommand.printGlobalUsage();
-    } else {
-      var name = commandOptions.rest[0];
-      var command = PubCommand.commands[name];
-      if (command == null) {
-        log.error('Could not find a command named "$name".');
-        log.error('Run "pub help" to see available commands.');
-        return flushThenExit(exit_codes.USAGE);
+      return null;
+    }
+
+    // Walk the command tree to show help for the selected command or
+    // subcommand.
+    var commands = PubCommand.mainCommands;
+    var command = null;
+    var commandString = "pub";
+
+    for (var name in commandOptions.rest) {
+      if (commands.isEmpty) {
+        command.usageError(
+            'Command "$commandString" does not expect a subcommand.');
       }
 
-      command.printUsage();
+      if (commands[name] == null) {
+        if (command == null) {
+          PubCommand.usageErrorWithCommands(commands,
+              'Could not find a command named "$name".');
+        }
+
+        command.usageError(
+            'Could not find a subcommand named "$name" for "$commandString".');
+      }
+
+      command = commands[name];
+      commands = command.subcommands;
+      commandString += " $name";
     }
+
+    command.printUsage();
   }
 }
diff --git a/sdk/lib/_internal/pub/lib/src/command/lish.dart b/sdk/lib/_internal/pub/lib/src/command/lish.dart
index bd9c445..d5e4676 100644
--- a/sdk/lib/_internal/pub/lib/src/command/lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/lish.dart
@@ -10,7 +10,6 @@
 
 import '../command.dart';
 import '../directory_tree.dart';
-import '../exit_codes.dart' as exit_codes;
 import '../http.dart';
 import '../io.dart';
 import '../log.dart' as log;
@@ -94,9 +93,7 @@
 
   Future onRun() {
     if (force && dryRun) {
-      log.error('Cannot use both --force and --dry-run.');
-      this.printUsage();
-      return flushThenExit(exit_codes.USAGE);
+      usageError('Cannot use both --force and --dry-run.');
     }
 
     var packageBytesFuture = entrypoint.packageFiles().then((files) {
@@ -144,15 +141,15 @@
 
       if (dryRun) {
         var s = warnings.length == 1 ? '' : 's';
-        log.warning("Package has ${warnings.length} warning$s.");
+        log.warning("\nPackage has ${warnings.length} warning$s.");
         return false;
       }
 
-      var message = 'Looks great! Are you ready to upload your package';
+      var message = '\nLooks great! Are you ready to upload your package';
 
       if (!warnings.isEmpty) {
         var s = warnings.length == 1 ? '' : 's';
-        message = "Package has ${warnings.length} warning$s. Upload anyway";
+        message = "\nPackage has ${warnings.length} warning$s. Upload anyway";
       }
 
       return confirm(message).then((confirmed) {
diff --git a/sdk/lib/_internal/pub/lib/src/git.dart b/sdk/lib/_internal/pub/lib/src/git.dart
index e94e493..4e92a69 100644
--- a/sdk/lib/_internal/pub/lib/src/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/git.dart
@@ -6,9 +6,13 @@
 library pub.git;
 
 import 'dart:async';
+import 'dart:io';
+
 import 'io.dart';
 import 'log.dart' as log;
 
+import 'package:stack_trace/stack_trace.dart';
+
 /// Tests whether or not the git command-line app is available for use.
 Future<bool> get isInstalled {
   if (_isGitInstalledCache != null) {
@@ -67,8 +71,13 @@
   return runProcess(command, ["--version"]).then((results) {
     var regexp = new RegExp("^git version");
     return results.stdout.length == 1 && regexp.hasMatch(results.stdout[0]);
-  }).catchError((err) {
+  }).catchError((err, stackTrace) {
     // If the process failed, they probably don't have it.
-    return false;
+    if (err is ProcessException) {
+      log.io('Git command is not "$command": $err\n$stackTrace');
+      return false;
+    }
+
+    throw err;
   });
 }
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index 3f17a02..79c2931 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -391,21 +391,13 @@
 /// symlink to the target. Otherwise, uses the [target] path unmodified.
 void createPackageSymlink(String name, String target, String symlink,
     {bool isSelfLink: false, bool relative: false}) {
-  // See if the package has a "lib" directory.
+  // See if the package has a "lib" directory. If not, there's nothing to
+  // symlink to.
   target = path.join(target, 'lib');
-  log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'.");
-  if (dirExists(target)) {
-    createSymlink(target, symlink, relative: relative);
-    return;
-  }
+  if (!dirExists(target)) return;
 
-  // It's OK for the self link (i.e. the root package) to not have a lib
-  // directory since it may just be a leaf application that only has
-  // code in bin or web.
-  if (!isSelfLink) {
-    log.warning('Warning: Package $name does not have a "lib" directory so '
-                'you will not be able to import any libraries from it.');
-  }
+  log.fine("Creating ${isSelfLink ? "self" : ""}link for package '$name'.");
+  createSymlink(target, symlink, relative: relative);
 }
 
 /// Whether pub is running from within the Dart SDK, as opposed to from the Dart
@@ -654,7 +646,7 @@
     executable = "cmd";
   }
 
-  log.process(executable, args);
+  log.process(executable, args, workingDir == null ? '.' : workingDir);
 
   return Chain.track(fn(executable,
       args,
diff --git a/sdk/lib/_internal/pub/lib/src/log.dart b/sdk/lib/_internal/pub/lib/src/log.dart
index bbbcb3c..0dcf088 100644
--- a/sdk/lib/_internal/pub/lib/src/log.dart
+++ b/sdk/lib/_internal/pub/lib/src/log.dart
@@ -8,6 +8,8 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:path/path.dart' as p;
+
 import 'io.dart';
 import 'transcript.dart';
 import 'utils.dart';
@@ -117,6 +119,13 @@
   if (_loggers.isEmpty) showNormal();
 
   var lines = splitLines(message.toString());
+
+  // Discard a trailing newline. This is useful since StringBuffers often end
+  // up with an extra newline at the end from using [writeln].
+  if (lines.isNotEmpty && lines.last == "") {
+    lines.removeLast();
+  }
+
   var entry = new Entry(level, lines);
 
   var logFn = _loggers[level];
@@ -152,30 +161,32 @@
 
 /// Logs the spawning of an [executable] process with [arguments] at [IO]
 /// level.
-void process(String executable, List<String> arguments) {
-  io("Spawning $executable ${arguments.join(' ')}");
+void process(String executable, List<String> arguments,
+    String workingDirectory) {
+  io("Spawning \"$executable ${arguments.join(' ')}\" in "
+      "${p.absolute(workingDirectory)}");
 }
 
 /// Logs the results of running [executable].
 void processResult(String executable, PubProcessResult result) {
   // Log it all as one message so that it shows up as a single unit in the logs.
   var buffer = new StringBuffer();
-  buffer.write("Finished $executable. Exit code ${result.exitCode}.");
+  buffer.writeln("Finished $executable. Exit code ${result.exitCode}.");
 
   dumpOutput(String name, List<String> output) {
     if (output.length == 0) {
-      buffer.write("Nothing output on $name.");
+      buffer.writeln("Nothing output on $name.");
     } else {
-      buffer.write("$name:");
+      buffer.writeln("$name:");
       var numLines = 0;
       for (var line in output) {
         if (++numLines > 1000) {
-          buffer.write('[${output.length - 1000}] more lines of output '
+          buffer.writeln('[${output.length - 1000}] more lines of output '
               'truncated...]');
           break;
         }
 
-        buffer.write(line);
+        buffer.writeln("| $line");
       }
     }
   }
@@ -183,7 +194,7 @@
   dumpOutput("stdout", result.stdout);
   dumpOutput("stderr", result.stderr);
 
-  io(buffer.toString());
+  io(buffer.toString().trim());
 }
 
 /// Enables recording of log entries.
diff --git a/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart b/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
index 6856878..53507de 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
@@ -39,12 +39,6 @@
 
   final _output = new StringBuffer();
 
-  /// To avoid emitting trailing newlines, we track if any are needed and only
-  /// emit then when text on the next line is about to be written.
-  // TODO(rnystrom): Move this into a separate class that wraps any StringSink
-  // with this logic.
-  int _pendingLines = 0;
-
   _SolveReport(this._sources, this._root, this._previousLockFile,
       this._result) {
     // Fill the map so we can use it later.
@@ -99,13 +93,13 @@
     var removed = _previousLockFile.packages.keys.toSet();
     removed.removeAll(names);
     if (removed.isNotEmpty) {
-      _writeln("These packages are no longer being depended on:");
+      _output.writeln("These packages are no longer being depended on:");
       removed = removed.toList();
       removed.sort();
       removed.forEach(_reportPackage);
     }
 
-    log.message(_output.toString());
+    log.message(_output);
   }
 
   /// Displays a warning about the overrides currently in effect.
@@ -113,14 +107,14 @@
     _output.clear();
 
     if (_result.overrides.isNotEmpty) {
-      _writeln("Warning: You are using these overridden dependencies:");
+      _output.writeln("Warning: You are using these overridden dependencies:");
       var overrides = _result.overrides.map((dep) => dep.name).toList();
       overrides.sort((a, b) => a.compareTo(b));
 
       overrides.forEach(
           (name) => _reportPackage(name, highlightOverride: false));
 
-      log.warning(_output.toString());
+      log.warning(_output);
     }
   }
 
@@ -149,39 +143,39 @@
     //     < The package was downgraded from a higher version.
     //     * Any other change between the old and new package.
     if (isOverridden) {
-      _write(log.magenta("! "));
+      _output.write(log.magenta("! "));
     } else if (newId == null) {
-      _write(log.red("- "));
+      _output.write(log.red("- "));
     } else if (oldId == null) {
-      _write(log.green("+ "));
+      _output.write(log.green("+ "));
     } else if (!_descriptionsEqual(oldId, newId)) {
-      _write(log.cyan("* "));
+      _output.write(log.cyan("* "));
       changed = true;
     } else if (oldId.version < newId.version) {
-      _write(log.green("> "));
+      _output.write(log.green("> "));
       changed = true;
     } else if (oldId.version > newId.version) {
-      _write(log.cyan("< "));
+      _output.write(log.cyan("< "));
       changed = true;
     } else {
       // Unchanged.
-      _write("  ");
+      _output.write("  ");
     }
 
-    _write(log.bold(id.name));
-    _write(" ");
+    _output.write(log.bold(id.name));
+    _output.write(" ");
     _writeId(id);
 
     // If the package was upgraded, show what it was upgraded from.
     if (changed) {
-      _write(" (was ");
+      _output.write(" (was ");
       _writeId(oldId);
-      _write(")");
+      _output.write(")");
     }
 
     // Highlight overridden packages.
     if (isOverridden && highlightOverride) {
-      _write(" ${log.magenta('(overridden)')}");
+      _output.write(" ${log.magenta('(overridden)')}");
     }
 
     // See if there are any newer versions of the package that we were
@@ -211,10 +205,10 @@
             "${pluralize('version', newerUnstable)} available)";
       }
 
-      if (message != null) _write(" ${log.cyan(message)}");
+      if (message != null) _output.write(" ${log.cyan(message)}");
     }
 
-    _writeln();
+    _output.writeln();
   }
 
   /// Returns `true` if [a] and [b] are from the same source and have the same
@@ -233,7 +227,7 @@
 
   /// Writes a terse description of [id] (not including its name) to the output.
   void _writeId(PackageId id) {
-    _write(id.version);
+    _output.write(id.version);
 
     var source = null;
     if (_sources.contains(id.source)) {
@@ -242,26 +236,7 @@
 
     if (source != null && source != _sources.defaultSource) {
       var description = source.formatDescription(_root.dir, id.description);
-      _write(" from ${id.source} $description");
+      _output.write(" from ${id.source} $description");
     }
   }
-
-  /// Writes [obj] to the output.
-  void _write(Object obj) {
-    while (_pendingLines > 0) {
-      _output.writeln();
-      _pendingLines--;
-    }
-    _output.write(obj);
-  }
-
-  /// Writes [obj] (if not null) followed by a newline to the output.
-  ///
-  /// Doesn't actually immediately write a newline. Instead, it waits until
-  /// output is written on the next line. That way, trailing newlines aren't
-  /// displayed.
-  void _writeln([Object obj]) {
-    if (obj != null) _write(obj);
-    _pendingLines++;
-  }
 }
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/lib/src/source/git.dart b/sdk/lib/_internal/pub/lib/src/source/git.dart
index c50e719..2981ebe 100644
--- a/sdk/lib/_internal/pub/lib/src/source/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/git.dart
@@ -130,8 +130,9 @@
 
   /// Returns a future that completes to the revision hash of [id].
   Future<String> _revisionAt(PackageId id) {
-    return git.run(["rev-parse", _getEffectiveRef(id)],
-        workingDir: _repoCachePath(id)).then((result) => result[0]);
+    return _ensureRepoCache(id).then((_) =>
+        git.run(["rev-parse", _getEffectiveRef(id)],
+            workingDir: _repoCachePath(id)).then((result) => result[0]));
   }
 
   /// Clones the repo at the URI [from] to the path [to] on the local
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 6d77713..c5f81c2 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -144,7 +144,14 @@
   var wrappedCallback = () {
     new Future.sync(callback).then(completer.complete)
         .catchError((e, stackTrace) {
-      completer.completeError(e, new Chain.forTrace(stackTrace));
+      // [stackTrace] can be null if we're running without [captureStackChains],
+      // since dart:io will often throw errors without stack traces.
+      if (stackTrace != null) {
+        stackTrace = new Chain.forTrace(stackTrace);
+      } else {
+        stackTrace = new Chain([]);
+      }
+      completer.completeError(e, stackTrace);
     });
   };
 
@@ -152,7 +159,12 @@
     Chain.capture(wrappedCallback, onError: completer.completeError);
   } else {
     runZoned(wrappedCallback, onError: (e, stackTrace) {
-      completer.completeError(e, new Chain([new Trace.from(stackTrace)]));
+      if (stackTrace == null) {
+        stackTrace = new Chain([new Trace.from(stackTrace)]);
+      } else {
+        stackTrace = new Chain([]);
+      }
+      completer.completeError(e, stackTrace);
     });
   }
 
@@ -841,6 +853,12 @@
   String toString() => message;
 }
 
+/// A class for command usage exceptions.
+class UsageException extends ApplicationException {
+  UsageException(String message)
+      : super(message);
+}
+
 /// An class for exceptions where a package could not be found in a [Source].
 ///
 /// The source is responsible for wrapping its internal exceptions in this so
diff --git a/sdk/lib/_internal/pub/test/get/git/locked_revision_without_repo_test.dart b/sdk/lib/_internal/pub/test/get/git/locked_revision_without_repo_test.dart
new file mode 100644
index 0000000..137e384
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/get/git/locked_revision_without_repo_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2012, 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.
+
+library pub_tests;
+
+import 'package:path/path.dart' as path;
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../../../lib/src/io.dart';
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+// Regression test for issue 16470.
+
+main() {
+  initConfig();
+  integration('checks out the repository for a locked revision', () {
+    ensureGit();
+
+    d.git('foo.git', [
+      d.libDir('foo'),
+      d.libPubspec('foo', '1.0.0')
+    ]).create();
+
+    d.appDir({"foo": {"git": "../foo.git"}}).create();
+
+    // This get should lock the foo.git dependency to the current revision.
+    pubGet();
+
+    d.dir(packagesPath, [
+      d.dir('foo', [
+        d.file('foo.dart', 'main() => "foo";')
+      ])
+    ]).validate();
+
+    // Delete the packages path and the cache to simulate a brand new checkout
+    // of the application.
+    schedule(() => deleteEntry(path.join(sandboxDir, packagesPath)));
+    schedule(() => deleteEntry(path.join(sandboxDir, cachePath)));
+
+    d.git('foo.git', [
+      d.libDir('foo', 'foo 2'),
+      d.libPubspec('foo', '1.0.0')
+    ]).commit();
+
+    // This get shouldn't upgrade the foo.git dependency due to the lockfile.
+    pubGet();
+
+    d.dir(packagesPath, [
+      d.dir('foo', [
+        d.file('foo.dart', 'main() => "foo";')
+      ])
+    ]).validate();
+  });
+}
diff --git a/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart b/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
index 26231e3..c436ff2 100644
--- a/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/force_cannot_be_combined_with_dry_run_test.dart
@@ -14,7 +14,16 @@
 
   integration('--force cannot be combined with --dry-run', () {
     schedulePub(args: ['lish', '--force', '--dry-run'],
-        error: "Cannot use both --force and --dry-run.",
+        error: """
+          Cannot use both --force and --dry-run.
+          
+          Usage: pub publish [options]
+          -h, --help       Print usage information for this command.
+          -n, --dry-run    Validate but do not publish the package.
+          -f, --force      Publish without confirmation if there are no errors.
+              --server     The package server to which to upload this package.
+                           (defaults to "https://pub.dartlang.org")
+          """,
         exitCode: exit_codes.USAGE);
   });
 }
diff --git a/sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart b/sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart
index d747b3b..a1c134d 100644
--- a/sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart
+++ b/sdk/lib/_internal/pub/test/lish/package_creation_provides_an_error_test.dart
@@ -7,7 +7,6 @@
 import 'package:scheduled_test/scheduled_test.dart';
 import 'package:scheduled_test/scheduled_server.dart';
 
-import '../../lib/src/exit_codes.dart' as exit_codes;
 import '../descriptor.dart' as d;
 import '../test_pub.dart';
 import 'utils.dart';
diff --git a/sdk/lib/_internal/pub/test/pub_cache_test.dart b/sdk/lib/_internal/pub/test/pub_cache_test.dart
index 91bc4a0..4483166 100644
--- a/sdk/lib/_internal/pub/test/pub_cache_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_cache_test.dart
@@ -17,30 +17,6 @@
         "pub.dartlang.org", package);
   }
 
-  integration('running pub cache displays error message', () {
-    schedulePub(args: ['cache'],
-        output: '''
-          Inspect the system cache.
-
-          Usage: pub cache list
-          -h, --help    Print usage information for this command.
-          ''',
-        error: 'The cache command expects one argument.',
-        exitCode: 64);
-  });
-
-  integration('running pub cache foo displays error message', () {
-    schedulePub(args: ['cache' ,'foo'],
-        output: '''
-          Inspect the system cache.
-
-          Usage: pub cache list
-          -h, --help    Print usage information for this command.
-          ''',
-        error: 'Unknown cache command "foo".',
-        exitCode: 64);
-  });
-
   integration('running pub cache list when there is no cache', () {
     schedulePub(args: ['cache', 'list'], output: '{"packages":{}}');
   });
diff --git a/sdk/lib/_internal/pub/test/pub_test.dart b/sdk/lib/_internal/pub/test/pub_test.dart
index 336e125..8c9e652 100644
--- a/sdk/lib/_internal/pub/test/pub_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_test.dart
@@ -6,12 +6,13 @@
 
 import 'package:scheduled_test/scheduled_test.dart';
 
+import '../lib/src/exit_codes.dart' as exit_codes;
 import 'test_pub.dart';
 
 final USAGE_STRING = """
     Pub is a package manager for Dart.
 
-    Usage: pub command [arguments]
+    Usage: pub <command> [arguments]
 
     Global options:
     -h, --help            Print this usage information.
@@ -27,7 +28,7 @@
     -v, --verbose         Shortcut for "--verbosity=all".
 
     Available commands:
-      build      Copy and compile all Dart entrypoints in the 'web' directory.
+      build      Apply transformers to build a package.
       get        Get the current package's dependencies.
       help       Display help information for Pub.
       publish    Publish the current package to pub.dartlang.org.
@@ -80,6 +81,21 @@
     ''');
   });
 
+  integration('running pub with --help after a command with subcommands shows '
+              'command usage', () {
+    schedulePub(args: ['cache', '--help'],
+        output: '''
+          Work with the system cache.
+          
+          Usage: pub cache <subcommand>
+          -h, --help    Print usage information for this command.
+          
+          Available subcommands:
+            list   List packages in the system cache.
+     ''');
+  });
+
+
   integration('running pub with just --version displays version', () {
     schedulePub(args: ['--version'], output: VERSION_STRING);
   });
@@ -88,9 +104,32 @@
     schedulePub(args: ['quylthulg'],
         error: '''
         Could not find a command named "quylthulg".
-        Run "pub help" to see available commands.
+   
+        Available commands:
+          build      Apply transformers to build a package.
+          get        Get the current package's dependencies.
+          help       Display help information for Pub.
+          publish    Publish the current package to pub.dartlang.org.
+          serve      Run a local web development server.
+          upgrade    Upgrade the current package's dependencies to latest versions.
+          uploader   Manage uploaders for a package on pub.dartlang.org.
+          version    Print pub version.
         ''',
-        exitCode: 64);
+        exitCode: exit_codes.USAGE);
+  });
+
+  integration('an unknown subcommand displays an error message', () {
+    schedulePub(args: ['cache', 'quylthulg'],
+        error: '''
+        Could not find a subcommand named "quylthulg" for "pub cache".
+   
+        Usage: pub cache <subcommand>
+        -h, --help    Print usage information for this command.
+        
+        Available subcommands:
+          list   List packages in the system cache.
+        ''',
+        exitCode: exit_codes.USAGE);
   });
 
   integration('an unknown option displays an error message', () {
@@ -99,7 +138,7 @@
         Could not find an option named "blorf".
         Run "pub help" to see available options.
         ''',
-        exitCode: 64);
+        exitCode: exit_codes.USAGE);
   });
 
   integration('an unknown command option displays an error message', () {
@@ -110,21 +149,32 @@
         Could not find an option named "blorf".
         Run "pub help" to see available options.
         ''',
-        exitCode: 64);
+        exitCode: exit_codes.USAGE);
   });
 
   integration('an unexpected argument displays an error message', () {
     schedulePub(args: ['version', 'unexpected'],
-        output: '''
-        Print pub version.
+        error: '''
+        Command "version" does not take any arguments.
 
         Usage: pub version
          -h, --help    Print usage information for this command.
         ''',
+        exitCode: exit_codes.USAGE);
+  });
+
+  integration('a missing subcommand displays an error message', () {
+    schedulePub(args: ['cache'],
         error: '''
-        Command "version" does not take any arguments.
+        Missing subcommand for "pub cache".
+
+        Usage: pub cache <subcommand>
+        -h, --help    Print usage information for this command.
+
+        Available subcommands:
+          list   List packages in the system cache.
         ''',
-        exitCode: 64);
+        exitCode: exit_codes.USAGE);
   });
 
   group('help', () {
@@ -157,15 +207,58 @@
             ''');
     });
 
+    integration('shows help for a subcommand', () {
+      schedulePub(args: ['help', 'cache', 'list'],
+          output: '''
+            List packages in the system cache.
+
+            Usage: pub cache list
+            -h, --help    Print usage information for this command.
+            ''');
+    });
+
     integration('an unknown help command displays an error message', () {
       schedulePub(args: ['help', 'quylthulg'],
           error: '''
             Could not find a command named "quylthulg".
-            Run "pub help" to see available commands.
+       
+            Available commands:
+              build      Apply transformers to build a package.
+              get        Get the current package's dependencies.
+              help       Display help information for Pub.
+              publish    Publish the current package to pub.dartlang.org.
+              serve      Run a local web development server.
+              upgrade    Upgrade the current package's dependencies to latest versions.
+              uploader   Manage uploaders for a package on pub.dartlang.org.
+              version    Print pub version.
             ''',
-            exitCode: 64);
+            exitCode: exit_codes.USAGE);
     });
 
+    integration('an unknown help subcommand displays an error message', () {
+      schedulePub(args: ['help', 'cache', 'quylthulg'],
+          error: '''
+            Could not find a subcommand named "quylthulg" for "pub cache".
+       
+            Usage: pub cache <subcommand>
+            -h, --help    Print usage information for this command.
+
+            Available subcommands:
+              list   List packages in the system cache.
+            ''',
+            exitCode: exit_codes.USAGE);
+    });
+
+    integration('an unexpected help subcommand displays an error message', () {
+      schedulePub(args: ['help', 'version', 'badsubcommand'],
+          error: '''
+            Command "pub version" does not expect a subcommand.
+            
+            Usage: pub version
+            -h, --help    Print usage information for this command.
+            ''',
+            exitCode: exit_codes.USAGE);
+    });
   });
 
   group('version', () {
diff --git a/sdk/lib/async/schedule_microtask.dart b/sdk/lib/async/schedule_microtask.dart
index 94a68c5..bd5312a 100644
--- a/sdk/lib/async/schedule_microtask.dart
+++ b/sdk/lib/async/schedule_microtask.dart
@@ -6,32 +6,45 @@
 
 typedef void _AsyncCallback();
 
-bool _callbacksAreEnqueued = false;
-Queue<_AsyncCallback> _asyncCallbacks = new Queue<_AsyncCallback>();
+class _AsyncCallbackEntry {
+  final _AsyncCallback callback;
+  _AsyncCallbackEntry next;
+  _AsyncCallbackEntry(this.callback);
+}
 
-void _asyncRunCallback() {
+_AsyncCallbackEntry _nextCallback;
+_AsyncCallbackEntry _lastCallback;
+
+void _asyncRunCallbackLoop() {
+  _AsyncCallbackEntry entry = _nextCallback;
   // As long as we are iterating over the registered callbacks we don't
-  // unset the [_callbacksAreEnqueued] boolean.
-  while (!_asyncCallbacks.isEmpty) {
-    Function callback = _asyncCallbacks.removeFirst();
-    try {
-      callback();
-    } catch (e) {
-      _AsyncRun._scheduleImmediate(_asyncRunCallback);
-      rethrow;
-    }
+  // set the [_lastCallback] entry.
+  while (entry != null) {
+    entry.callback();
+    entry = _nextCallback = entry.next;
   }
   // Any new callback must register a callback function now.
-  _callbacksAreEnqueued = false;
+  _lastCallback = null;
+}
+
+void _asyncRunCallback() {
+  try {
+    _asyncRunCallbackLoop();
+  } catch (e) {
+    _AsyncRun._scheduleImmediate(_asyncRunCallback);
+    _nextCallback = _nextCallback.next;
+    rethrow;
+  }
 }
 
 void _scheduleAsyncCallback(callback) {
   // Optimizing a group of Timer.run callbacks to be executed in the
   // same Timer callback.
-  _asyncCallbacks.add(callback);
-  if (!_callbacksAreEnqueued) {
+  if (_lastCallback == null) {
+    _nextCallback = _lastCallback = new _AsyncCallbackEntry(callback);
     _AsyncRun._scheduleImmediate(_asyncRunCallback);
-    _callbacksAreEnqueued = true;
+  } else {
+    _lastCallback = _lastCallback.next = new _AsyncCallbackEntry(callback);
   }
 }
 
diff --git a/sdk/lib/convert/utf.dart b/sdk/lib/convert/utf.dart
index 8e480f8..2f513b0 100644
--- a/sdk/lib/convert/utf.dart
+++ b/sdk/lib/convert/utf.dart
@@ -133,8 +133,13 @@
   _Utf8Encoder() : this.withBufferSize(_DEFAULT_BYTE_BUFFER_SIZE);
 
   _Utf8Encoder.withBufferSize(int bufferSize)
-      // TODO(11971, floitsch): use Uint8List instead of normal lists.
-      : _buffer = new List<int>(bufferSize);
+      : _buffer = _createBuffer(bufferSize);
+
+  // TODO(11971): Always use Uint8List.
+  /**
+   * Allow an implementation to pick the most efficient way of storing bytes.
+   */
+  external static List<int> _createBuffer(int size);
 
   /**
    * Tries to combine the given [leadingSurrogate] with the [nextCodeUnit] and
diff --git a/sdk/lib/core/errors.dart b/sdk/lib/core/errors.dart
index 8c2c61d..905250c 100644
--- a/sdk/lib/core/errors.dart
+++ b/sdk/lib/core/errors.dart
@@ -9,6 +9,7 @@
  *
  * An `Error` object represents a program failure that the programmer
  * should have avoided.
+ *
  * Examples include calling a function with invalid arguments,
  * or even with the wrong number of arguments,
  * or calling it at a time when it is not allowed.
@@ -50,7 +51,7 @@
  * the stack trace at the throw point is recorded
  * and stored in the error object.
  * It can be retrieved using the [stackTrace] getter.
- * Errors that merely implement `Error`, and doesn't extend it,
+ * An error object that merely implements `Error`, and doesn't extend it,
  * will not store the stack trace automatically.
  *
  * Error objects are also used for system wide failures
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index f966796..43fc262 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -32418,13 +32418,14 @@
     _tryResume();
   }
 
-  void cancel() {
-    if (_canceled) return;
+  Future cancel() {
+    if (_canceled) return null;
 
     _unlisten();
     // Clear out the target to indicate this is complete.
     _target = null;
     _onData = null;
+    return null;
   }
 
   bool get _canceled => _target == null;
@@ -34051,7 +34052,7 @@
    * KeyboardEvent controller.
    */
   _KeyboardEventHandler(this._type): super(_EVENT_TYPE),
-      _stream = new _CustomKeyEventStreamImpl('event');
+      _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
 
   /**
    * Hook up all event listeners under the covers so we can estimate keycodes
@@ -35114,6 +35115,10 @@
   return (receiver) {
     setNativeSubclassDispatchRecord(receiver, interceptor);
 
+    // Mirrors uses the constructor property to cache lookups, so we need it to
+    // be set correctly, including on IE where it is not automatically picked
+    // up from the __proto__.
+    JS('', '#.constructor = #.__proto__.constructor', receiver, receiver);
     return JS('', '#(#)', constructor, receiver);
   };
 }
@@ -35656,14 +35661,16 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-_wrapZone(callback) {
+_wrapZone(callback(arg)) {
   // For performance reasons avoid wrapping if we are in the root zone.
   if (Zone.current == Zone.ROOT) return callback;
+  if (callback == null) return null;
   return Zone.current.bindUnaryCallback(callback, runGuarded: true);
 }
 
-_wrapBinaryZone(callback) {
+_wrapBinaryZone(callback(arg1, arg2)) {
   if (Zone.current == Zone.ROOT) return callback;
+  if (callback == null) return null;
   return Zone.current.bindBinaryCallback(callback, runGuarded: true);
 }
 
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 62f36b9..52544f0 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -35098,13 +35098,14 @@
     _tryResume();
   }
 
-  void cancel() {
-    if (_canceled) return;
+  Future cancel() {
+    if (_canceled) return null;
 
     _unlisten();
     // Clear out the target to indicate this is complete.
     _target = null;
     _onData = null;
+    return null;
   }
 
   bool get _canceled => _target == null;
@@ -36731,7 +36732,7 @@
    * KeyboardEvent controller.
    */
   _KeyboardEventHandler(this._type): super(_EVENT_TYPE),
-      _stream = new _CustomKeyEventStreamImpl('event');
+      _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
 
   /**
    * Hook up all event listeners under the covers so we can estimate keycodes
@@ -38053,14 +38054,16 @@
 // BSD-style license that can be found in the LICENSE file.
 
 
-_wrapZone(callback) {
+_wrapZone(callback(arg)) {
   // For performance reasons avoid wrapping if we are in the root zone.
   if (Zone.current == Zone.ROOT) return callback;
+  if (callback == null) return null;
   return Zone.current.bindUnaryCallback(callback, runGuarded: true);
 }
 
-_wrapBinaryZone(callback) {
+_wrapBinaryZone(callback(arg1, arg2)) {
   if (Zone.current == Zone.ROOT) return callback;
+  if (callback == null) return null;
   return Zone.current.bindBinaryCallback(callback, runGuarded: true);
 }
 
@@ -38522,7 +38525,7 @@
     // TODO(vsm): Move these checks into native code.
     ClassMirror cls = reflectClass(type);
     if (_isBuiltinType(cls)) {
-      throw new UnsupportedError("Invalid custom element from $libName.");
+      throw new UnsupportedError("Invalid custom element from ${cls.owner.uri}.");
     }
     var className = MirrorSystem.getName(cls.simpleName);
     var createdConstructor = cls.declarations[new Symbol('$className.created')];
@@ -38629,6 +38632,9 @@
   int get length => Maps.length(this);
   bool get isEmpty => Maps.isEmpty(this);
   bool get isNotEmpty => Maps.isNotEmpty(this);
+  void addAll(Map<String, String> other) {
+    other.forEach((key, value) => this[key] = value);
+  }
 }
 
 final _printClosure = window.console.log;
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 1912d61..9a657a1 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -35,6 +35,8 @@
   static const _MODE = 4;
   static const _SIZE = 5;
 
+  static const _notFound = const FileStat._internalNotFound();
+
   /**
    * The time of the last change to the data or metadata of the file system
    * object.  On Windows platforms, this is instead the file creation time.
@@ -73,7 +75,11 @@
                      this.mode,
                      this.size);
 
-  external static List<int> _statSync(String path);
+  const FileStat._internalNotFound() :
+      changed = null,  modified = null, accessed = null,
+      type = FileSystemEntityType.NOT_FOUND, mode = 0, size = -1;
+
+  external static _statSync(String path);
 
 
   /**
@@ -88,7 +94,7 @@
       path = FileSystemEntity._trimTrailingPathSeparators(path);
     }
     var data = _statSync(path);
-    if (data is OSError) throw data;
+    if (data is OSError) return FileStat._notFound;
     return new FileStat._internal(
         new DateTime.fromMillisecondsSinceEpoch(data[_CHANGED_TIME] * 1000),
         new DateTime.fromMillisecondsSinceEpoch(data[_MODIFIED_TIME] * 1000),
@@ -112,9 +118,7 @@
     }
     return _IOService.dispatch(_FILE_STAT, [path]).then((response) {
       if (_isErrorResponse(response)) {
-        throw _exceptionFromResponse(response,
-                                     "Error getting stat",
-                                     path);
+        return FileStat._notFound;
       }
       // Unwrap the real list from the "I'm not an error" wrapper.
       List data = response[1];
diff --git a/sdk/lib/io/http_headers.dart b/sdk/lib/io/http_headers.dart
index 1d7e9b5..0be5c08 100644
--- a/sdk/lib/io/http_headers.dart
+++ b/sdk/lib/io/http_headers.dart
@@ -444,7 +444,7 @@
     void parseCookieString(String s) {
       int index = 0;
 
-      bool done() => index == s.length;
+      bool done() => index == -1 || index == s.length;
 
       void skipWS() {
         while (!done()) {
@@ -471,14 +471,11 @@
         return s.substring(start, index);
       }
 
-      void expect(String expected) {
-        if (done()) {
-          throw new HttpException("Failed to parse header value [$s]");
-        }
-        if (s[index] != expected) {
-          throw new HttpException("Failed to parse header value [$s]");
-        }
+      bool expect(String expected) {
+        if (done()) return false;
+        if (s[index] != expected) return false;
         index++;
+        return true;
       }
 
       while (!done()) {
@@ -486,13 +483,19 @@
         if (done()) return;
         String name = parseName();
         skipWS();
-        expect("=");
+        if (!expect("=")) {
+          index = s.indexOf(';', index);
+          continue;
+        }
         skipWS();
         String value = parseValue();
         cookies.add(new _Cookie(name, value));
         skipWS();
         if (done()) return;
-        expect(";");
+        if (!expect(";")) {
+          index = s.indexOf(';', index);
+          continue;
+        }
       }
     }
     List<String> values = _headers[HttpHeaders.COOKIE];
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index 8856c10..5c3263f 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -96,68 +96,119 @@
   static const int RESPONSE = 0;
 }
 
-class _HttpDetachedIncoming extends Stream<List<int>> {
-  StreamController<List<int>> controller;
-  final StreamSubscription subscription;
 
-  List<int> bufferedData;
-  bool paused;
+/**
+ * The _HttpDetachedStreamSubscription takes a subscription and some extra data,
+ * and makes it possible to "inject" the data in from of other data events
+ * from the subscription.
+ *
+ * It does so by overriding pause/resume, so that once the
+ * _HttpDetachedStreamSubscription is resumed, it'll deliver the data before
+ * resuming the underlaying subscription.
+ */
+class _HttpDetachedStreamSubscription implements StreamSubscription<List<int>> {
+  StreamSubscription<List<int>> _subscription;
+  List<int> _injectData;
+  bool _isCanceled = false;
+  int _pauseCount = 1;
+  Function _userOnData;
+  bool _scheduled = false;
 
-  Completer resumeCompleter;
+  _HttpDetachedStreamSubscription(this._subscription,
+                                  this._injectData,
+                                  this._userOnData);
 
-  _HttpDetachedIncoming(this.subscription, this.bufferedData) {
-    controller = new StreamController<List<int>>(
-        sync: true,
-        onListen: resume,
-        onPause: pause,
-        onResume: resume,
-        onCancel: () => subscription.cancel());
-    if (subscription == null) {
-      // Socket was already closed.
-      if (bufferedData != null) controller.add(bufferedData);
-      controller.close();
+  bool get isPaused => _subscription.isPaused;
+
+  Future asFuture([futureValue]) => _subscription.asFuture(futureValue);
+
+  Future cancel() {
+    _isCanceled = true;
+    _injectData = null;
+    return _subscription.cancel();
+  }
+
+  void onData(void handleData(List<int> data)) {
+    _userOnData = handleData;
+    _subscription.onData(handleData);
+  }
+
+  void onDone(void handleDone()) {
+    _subscription.onDone(handleDone);
+  }
+
+  void onError(Function handleError) {
+    _subscription.onError(handleError);
+  }
+
+  void pause([Future resumeSignal]) {
+    if (_injectData == null) {
+      _subscription.pause(resumeSignal);
     } else {
-      pause();
-      subscription
-          ..resume()
-          ..onData(controller.add)
-          ..onDone(controller.close)
-          ..onError(controller.addError);
+      _pauseCount++;
+      if (resumeSignal != null) {
+        resumeSignal.whenComplete(resume);
+      }
     }
   }
 
+  void resume() {
+    if (_injectData == null) {
+      _subscription.resume();
+    } else {
+      _pauseCount--;
+      _maybeScheduleData();
+    }
+  }
+
+  void _maybeScheduleData() {
+    if (_scheduled) return;
+    if (_pauseCount != 0) return;
+    _scheduled = true;
+    scheduleMicrotask(() {
+      _scheduled = false;
+      if (_pauseCount > 0 || _isCanceled) return;
+      var data = _injectData;
+      _injectData = null;
+      // To ensure that 'subscription.isPaused' is false, we resume the
+      // subscription here. This is fine as potential events are delayed.
+      _subscription.resume();
+      if (_userOnData != null) {
+        _userOnData(data);
+      }
+    });
+  }
+}
+
+
+class _HttpDetachedIncoming extends Stream<List<int>> {
+  final StreamSubscription subscription;
+  final List<int> bufferedData;
+
+  _HttpDetachedIncoming(this.subscription, this.bufferedData);
+
   StreamSubscription<List<int>> listen(void onData(List<int> event),
                                        {Function onError,
                                         void onDone(),
                                         bool cancelOnError}) {
-    return controller.stream.listen(
-        onData,
-        onError: onError,
-        onDone: onDone,
-        cancelOnError: cancelOnError);
-  }
-
-  void resume() {
-    paused = false;
-    if (bufferedData != null) {
-      var data = bufferedData;
-      bufferedData = null;
-      controller.add(data);
-      // If the consumer pauses again after the carry-over data, we'll not
-      // continue our subscriber until the next resume.
-      if (paused) return;
-    }
-    if (resumeCompleter != null) {
-      resumeCompleter.complete();
-      resumeCompleter = null;
-    }
-  }
-
-  void pause() {
-    paused = true;
-    if (resumeCompleter == null) {
-      resumeCompleter = new Completer();
-      subscription.pause(resumeCompleter.future);
+    if (subscription != null) {
+      subscription
+        ..onData(onData)
+        ..onError(onError)
+        ..onDone(onDone);
+      if (bufferedData == null) {
+        return subscription..resume();
+      }
+      return new _HttpDetachedStreamSubscription(subscription,
+                                                 bufferedData,
+                                                 onData)
+        ..resume();
+    } else {
+      return new Stream.fromIterable(bufferedData)
+          .listen(onData,
+                  onError: onError,
+                  onDone: onDone,
+                  cancelOnError: cancelOnError);
     }
   }
 }
@@ -833,6 +884,8 @@
   void set responseToMethod(String method) { _responseToMethod = method; }
 
   _HttpDetachedIncoming detachIncoming() {
+    // Simulate detached by marking as upgraded.
+    _state = _State.UPGRADED;
     return new _HttpDetachedIncoming(_socketSubscription,
                                      readUnparsedData());
   }
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 75bd893..0cf7126 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -346,6 +346,20 @@
 
   String toString() => _name;
 
+  /**
+   * Watch for process signals.
+   *
+   * The following [ProcessSignal]s can be listened to:
+   *
+   *   * [ProcessSignal.SIGHUP].
+   *   * [ProcessSignal.SIGINT].
+   *   * [ProcessSignal.SIGTERM]. Not available on Windows.
+   *   * [ProcessSignal.SIGUSR1]. Not available on Windows.
+   *   * [ProcessSignal.SIGUSR2]. Not available on Windows.
+   *   * [ProcessSignal.SIGWINCH]. Not available on Windows.
+   *
+   * Other signals are disallowed, as they may be used by the VM.
+   */
   Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this);
 }
 
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 5396a6a..495c70e 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -128,6 +128,7 @@
   static int _idCount = 0;
 
   static RawReceivePort _receivePort;
+  static SendPort _sendPort;
   static bool _handlingCallbacks = false;
 
   Function _callback;
@@ -241,10 +242,13 @@
         // events.
         _createTimerHandler();
       }
-      _EventHandler._sendData(null,
-                              _receivePort,
-                              _firstZeroTimer != null ?
-                                  0 : _heap.first._wakeupTime);
+      if (_firstZeroTimer != null) {
+        _sendPort.send(null);
+      } else {
+        _EventHandler._sendData(null,
+                                _receivePort,
+                                _heap.first._wakeupTime);
+      }
     }
   }
 
@@ -300,6 +304,7 @@
   static void _createTimerHandler() {
     if(_receivePort == null) {
       _receivePort = new RawReceivePort(_handleTimeout);
+      _sendPort = _receivePort.sendPort;
     }
   }
 
diff --git a/sdk/lib/isolate/capability.dart b/sdk/lib/isolate/capability.dart
new file mode 100644
index 0000000..a51eec2
--- /dev/null
+++ b/sdk/lib/isolate/capability.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2014, 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 dart.isolate;
+
+/**
+ * An unforgeable object that comes back as equal when passed through other
+ * isolates.
+ *
+ * Sending a capability object to another isolate, and getting it back,
+ * will produce an object that is equal to the original.
+ * There is no other way to create objects equal to a capability object.
+ *
+ * Capabilities can be used as access guards: A remote isolate can send
+ * a request for an operation, but it is only allowed if the request contains
+ * the correct capability object.
+ *
+ * This allows exposing the same interface to multiple clients,
+ * but restricting some operations to only those clients
+ * that have also been given the corresponding capability.
+ *
+ * Capabilities can be used inside a single isolate,
+ * but they have no advantage over
+ * just using `new Object` to create a unique object,
+ * and it offers no real security against other code
+ * running in the same isolate.
+ */
+class Capability {
+  /**
+   * Create a new unforgeable capability object.
+   */
+  external factory Capability();
+}
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index efc6ca2..4a5b50a 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -16,6 +16,8 @@
 
 import "dart:async";
 
+part "capability.dart";
+
 /**
  * Thrown when an isolate cannot be created.
  */
@@ -27,11 +29,16 @@
 }
 
 class Isolate {
+  /**
+   * Control port used to send control messages to the isolate.
+   *
+   * This class provides helper functions that sends control messages
+   * to the control port.
+   */
+  final SendPort controlPort;
+  final Capability pauseCapability;
 
-  final SendPort _controlPort;
-
-  Isolate._fromControlPort(SendPort controlPort)
-      : this._controlPort = controlPort;
+  Isolate._fromControlPort(this.controlPort, [this.pauseCapability]);
 
   /**
    * Creates and spawns an isolate that shares the same code as the current
@@ -74,6 +81,57 @@
    */
   external static Future<Isolate> spawnUri(
       Uri uri, List<String> args, var message);
+
+
+  /**
+   * Requests the isolate to pause.
+   *
+   * The isolate should stop handling events by pausing its event queue.
+   * The request will eventually make the isolate stop doing anything.
+   * It will be handled before any other messages sent to the isolate from
+   * the current isolate, but no other guarantees are provided.
+   *
+   * If [resumeCapability] is provided, it is used to identity the pause,
+   * and must be used again to end the pause using [resume].
+   * Otherwise a new capability is created and returned.
+   *
+   * If an isolate is paused more than once using the same capabilty,
+   * only one resume with that capability is needed to end the pause.
+   *
+   * If an isolate is paused using more than one capability,
+   * they must all be individully ended before the isolate resumes.
+   *
+   * Returns the capability that must be used to resume end the pause.
+   *
+   * WARNING: This method is not handled on any platform yet.
+   */
+  Capability pause([Capability resumeCapability]) {
+    if (resumeCapability == null) resumeCapability = new Capability();
+    var message = new List(3)
+        ..[0] = "pause"
+        ..[1] = pauseCapability
+        ..[2] = resumeCapability;
+    controlPort.send(message);
+    return resumeCapability;
+  }
+
+  /**
+   * Resumes a paused isolate.
+   *
+   * Sends a message to an isolate requesting that it ends a pause
+   * that was requested using the [resumeCapability].
+   *
+   * The capability must be one returned by a call to [pause] on this
+   * isolate, otherwise the resume call does nothing.
+   *
+   * WARNING: This method is not handled on any platform yet.
+   */
+  void resume(Capability resumeCapability) {
+    var message = new List(2)
+        ..[0] = "resume"
+        ..[1] = resumeCapability;
+    controlPort.send(message);
+  }
 }
 
 /**
diff --git a/sdk/lib/isolate/isolate_sources.gypi b/sdk/lib/isolate/isolate_sources.gypi
index e1c4825..8d3ff84 100644
--- a/sdk/lib/isolate/isolate_sources.gypi
+++ b/sdk/lib/isolate/isolate_sources.gypi
@@ -6,5 +6,6 @@
   'sources': [
     'isolate.dart',
     # The above file needs to be first as it lists the parts below.
+    'capability.dart',
   ],
 }
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
index b1003d9..576cb234 100644
--- a/sdk/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/js/dart2js/js_dart2js.dart
@@ -471,6 +471,13 @@
   return false;
 }
 
+Object _getOwnProperty(o, String name) {
+  if (JS('bool', 'Object.prototype.hasOwnProperty.call(#, #)', o, name)) {
+    return JS('', '#[#]', o, name);
+  }
+  return null;
+}
+
 bool _isLocalObject(o) => JS('bool', '# instanceof Object', o);
 
 dynamic _convertToJS(dynamic o) {
@@ -498,7 +505,7 @@
 }
 
 Object _getJsProxy(o, String propertyName, createProxy(o)) {
-  var jsProxy = JS('', '#[#]', o, propertyName);
+  var jsProxy = _getOwnProperty(o, propertyName);
   if (jsProxy == null) {
     jsProxy = createProxy(o);
     _defineProperty(o, propertyName, jsProxy);
@@ -543,7 +550,7 @@
 }
 
 Object _getDartProxy(o, String propertyName, createProxy(o)) {
-  var dartProxy = JS('', '#[#]', o, propertyName);
+  var dartProxy = _getOwnProperty(o, propertyName);
   // Temporary fix for dartbug.com/15193
   // In some cases it's possible to see a JavaScript object that
   // came from a different context and was previously proxied to
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index 7e0b50b..a2764d7 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -814,7 +814,7 @@
 
   int get offsetInBytes => _storage.offsetInBytes;
 
-  final int elementSizeInBytes = 16;
+  int get elementSizeInBytes => BYTES_PER_ELEMENT;
 
   void _invalidIndex(int index, int length) {
     if (index < 0 || index >= length) {
@@ -892,7 +892,8 @@
    */
   Float32x4List.view(ByteBuffer buffer,
                      [int byteOffset = 0, int length])
-      : _storage = new Float32List.view(buffer, byteOffset, length);
+      : _storage = new Float32List.view(buffer, byteOffset,
+                                        length != null ? length * 4 : null);
 
   static const int BYTES_PER_ELEMENT = 16;
 
@@ -940,7 +941,7 @@
 
   int get offsetInBytes => _storage.offsetInBytes;
 
-  final int elementSizeInBytes = 16;
+  int get elementSizeInBytes => BYTES_PER_ELEMENT;
 
   void _invalidIndex(int index, int length) {
     if (index < 0 || index >= length) {
@@ -1019,7 +1020,8 @@
    */
   Int32x4List.view(ByteBuffer buffer,
                      [int byteOffset = 0, int length])
-      : _storage = new Uint32List.view(buffer, byteOffset, length);
+      : _storage = new Uint32List.view(buffer, byteOffset,
+                                       length != null ? length * 4 : null);
 
   static const int BYTES_PER_ELEMENT = 16;
 
@@ -1050,6 +1052,127 @@
 
 
 /**
+ * A fixed-length list of Float64x2 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+class Float64x2List
+    extends Object with ListMixin<Float64x2>, FixedLengthListMixin<Float64x2>
+    implements List<Float64x2>, TypedData {
+
+  final Float64List _storage;
+
+  ByteBuffer get buffer => _storage.buffer;
+
+  int get lengthInBytes => _storage.lengthInBytes;
+
+  int get offsetInBytes => _storage.offsetInBytes;
+
+  int get elementSizeInBytes => BYTES_PER_ELEMENT;
+
+  void _invalidIndex(int index, int length) {
+    if (index < 0 || index >= length) {
+      throw new RangeError.range(index, 0, length);
+    } else {
+      throw new ArgumentError('Invalid list index $index');
+    }
+  }
+
+  void _checkIndex(int index, int length) {
+    if (JS('bool', '(# >>> 0 != #)', index, index) || index >= length) {
+      _invalidIndex(index, length);
+    }
+  }
+
+  int _checkSublistArguments(int start, int end, int length) {
+    // For `sublist` the [start] and [end] indices are allowed to be equal to
+    // [length]. However, [_checkIndex] only allows indices in the range
+    // 0 .. length - 1. We therefore increment the [length] argument by one
+    // for the [_checkIndex] checks.
+    _checkIndex(start, length + 1);
+    if (end == null) return length;
+    _checkIndex(end, length + 1);
+    if (start > end) throw new RangeError.range(start, 0, end);
+    return end;
+  }
+
+  /**
+   * Creates a [Float64x2List] of the specified length (in elements),
+   * all of whose elements are initially zero.
+   */
+  Float64x2List(int length) : _storage = new Float64List(length * 2);
+
+  Float64x2List._externalStorage(Float64List storage) : _storage = storage;
+
+  Float64x2List._slowFromList(List<Float64x2> list)
+      : _storage = new Float64List(list.length * 2) {
+    for (int i = 0; i < list.length; i++) {
+      var e = list[i];
+      _storage[(i * 2) + 0] = e.x;
+      _storage[(i * 2) + 1] = e.y;
+    }
+  }
+
+  /**
+   * Creates a [Float64x2List] with the same size as the [elements] list
+   * and copies over the elements.
+   */
+  factory Float64x2List.fromList(List<Float64x2> list) {
+    if (list is Float64x2List) {
+      Float64x2List nativeList = list as Float64x2List;
+      return new Float64x2List._externalStorage(
+          new Float64List.fromList(nativeList._storage));
+    } else {
+      return new Float64x2List._slowFromList(list);
+    }
+  }
+
+  /**
+   * Creates a [Float64x2List] _view_ of the specified region in the specified
+   * byte buffer. Changes in the [Float64x2List] will be visible in the byte
+   * buffer and vice versa. If the [offsetInBytes] index of the region is not
+   * specified, it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to null, which indicates
+   * that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * BYTES_PER_ELEMENT.
+   */
+  Float64x2List.view(ByteBuffer buffer,
+                     [int byteOffset = 0, int length])
+      : _storage = new Float64List.view(buffer, byteOffset,
+                                        length != null ? length * 2 : null);
+
+  static const int BYTES_PER_ELEMENT = 16;
+
+  int get length => _storage.length ~/ 2;
+
+  Float64x2 operator[](int index) {
+    _checkIndex(index, length);
+    double _x = _storage[(index * 2) + 0];
+    double _y = _storage[(index * 2) + 1];
+    return new Float64x2(_x, _y);
+  }
+
+  void operator[]=(int index, Float64x2 value) {
+    _checkIndex(index, length);
+    _storage[(index * 2) + 0] = value._storage[0];
+    _storage[(index * 2) + 1] = value._storage[1];
+  }
+
+  List<Float64x2> sublist(int start, [int end]) {
+    end = _checkSublistArguments(start, end, length);
+    return new Float64x2List._externalStorage(
+        _storage.sublist(start * 2, end * 2));
+  }
+}
+
+
+/**
  * Interface of Dart Float32x4 immutable value type and operations.
  * Float32x4 stores 4 32-bit floating point values in "lanes".
  * The lanes are "x", "y", "z", and "w" respectively.
@@ -1078,6 +1201,14 @@
     _storage[2] = view[2];
     _storage[3] = view[3];
   }
+  Float32x4.fromFloat64x2(Float64x2 v) {
+    _storage[0] = v._storage[0];
+    _storage[1] = v._storage[1];
+  }
+
+  String toString() {
+    return '[${_storage[0]}, ${_storage[1]}, ${_storage[2]}, ${_storage[3]}]';
+  }
 
    /// Addition operator.
   Float32x4 operator+(Float32x4 other) {
@@ -1665,6 +1796,10 @@
     _storage[3] = view[3];
   }
 
+  String toString() {
+    return '[${_storage[0]}, ${_storage[1]}, ${_storage[2]}, ${_storage[3]}]';
+  }
+
   /// The bit-wise or operator.
   Int32x4 operator|(Int32x4 other) {
     int _x = _storage[0] | other._storage[0];
@@ -2124,3 +2259,126 @@
     return r;
   }
 }
+
+class Float64x2 {
+  final _storage = new Float64List(2);
+
+  Float64x2(double x, double y) {
+    _storage[0] = x;
+    _storage[1] = y;
+  }
+
+  Float64x2.splat(double v) {
+    _storage[0] = v;
+    _storage[1] = v;
+  }
+
+  Float64x2.zero();
+
+  Float64x2.fromFloat32x4(Float32x4 v) {
+    _storage[0] = v._storage[0];
+    _storage[1] = v._storage[1];
+  }
+
+  String toString() {
+    return '[${_storage[0]}, ${_storage[1]}]';
+  }
+
+  /// Addition operator.
+  Float64x2 operator+(Float64x2 other) {
+    return new Float64x2(_storage[0] + other._storage[0],
+                         _storage[1] + other._storage[1]);
+  }
+
+  /// Negate operator.
+  Float64x2 operator-() {
+    return new Float64x2(-_storage[0], -_storage[1]);
+  }
+
+  /// Subtraction operator.
+  Float64x2 operator-(Float64x2 other) {
+    return new Float64x2(_storage[0] - other._storage[0],
+                         _storage[1] - other._storage[1]);
+  }
+  /// Multiplication operator.
+  Float64x2 operator*(Float64x2 other) {
+    return new Float64x2(_storage[0] * other._storage[0],
+                         _storage[1] * other._storage[1]);
+  }
+  /// Division operator.
+  Float64x2 operator/(Float64x2 other) {
+    return new Float64x2(_storage[0] / other._storage[0],
+                         _storage[1] / other._storage[1]);
+  }
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  Float64x2 scale(double s) {
+    return new Float64x2(_storage[0] * s, _storage[1] * s);
+  }
+
+  /// Returns the absolute value of this [Float64x2].
+  Float64x2 abs() {
+    return new Float64x2(_storage[0].abs(), _storage[1].abs());
+  }
+
+  /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
+  Float64x2 clamp(Float64x2 lowerLimit,
+                  Float64x2 upperLimit) {
+    double _lx = lowerLimit._storage[0];
+    double _ly = lowerLimit._storage[1];
+    double _ux = upperLimit._storage[0];
+    double _uy = upperLimit._storage[1];
+    double _x = _storage[0];
+    double _y = _storage[1];
+    // MAX(MIN(self, upper), lower).
+    _x = _x > _ux ? _ux : _x;
+    _y = _y > _uy ? _uy : _y;
+    _x = _x < _lx ? _lx : _x;
+    _y = _y < _ly ? _ly : _y;
+    return new Float64x2(_x, _y);
+  }
+
+  /// Extracted x value.
+  double get x => _storage[0];
+  /// Extracted y value.
+  double get y => _storage[1];
+
+  /// Extract the sign bits from each lane return them in the first 2 bits.
+  int get signMask {
+    var view = new Uint32List.view(_storage.buffer);
+    var mx = (view[1] & 0x80000000) >> 31;
+    var my = (view[3] & 0x80000000) >> 31;
+    return mx | my << 1;
+  }
+
+  /// Returns a new [Float64x2] copied from [this] with a new x value.
+  Float64x2 withX(double x) {
+    return new Float64x2(x, _storage[1]);
+  }
+
+  /// Returns a new [Float64x2] copied from [this] with a new y value.
+  Float64x2 withY(double y) {
+    return new Float64x2(_storage[0], y);
+  }
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float64x2 min(Float64x2 other) {
+    return new Float64x2(
+        _storage[0] < other._storage[0] ? _storage[0] : other._storage[0],
+        _storage[1] < other._storage[1] ? _storage[1] : other._storage[1]);
+
+  }
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float64x2 max(Float64x2 other) {
+    return new Float64x2(
+        _storage[0] > other._storage[0] ? _storage[0] : other._storage[0],
+        _storage[1] > other._storage[1] ? _storage[1] : other._storage[1]);
+  }
+
+  /// Returns the lane-wise square root of [this].
+  Float64x2 sqrt() {
+      return new Float64x2(Math.sqrt(_storage[0]), Math.sqrt(_storage[1]));
+  }
+}
+
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 413eff3..66a86bc 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -364,7 +364,7 @@
   external factory Int8List(int length);
 
   /**
-   * Creates a [Int8List] with the same size as the [elements] list
+   * Creates a [Int8List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Int8List.fromList(List<int> elements);
@@ -401,7 +401,7 @@
   external factory Uint8List(int length);
 
   /**
-   * Creates a [Uint8List] with the same size as the [elements] list
+   * Creates a [Uint8List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Uint8List.fromList(List<int> elements);
@@ -476,7 +476,7 @@
   external factory Int16List(int length);
 
   /**
-   * Creates a [Int16List] with the same size as the [elements] list
+   * Creates a [Int16List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Int16List.fromList(List<int> elements);
@@ -494,7 +494,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Int16List.view(ByteBuffer buffer,
                                   [int offsetInBytes = 0, int length]);
@@ -516,7 +516,7 @@
   external factory Uint16List(int length);
 
   /**
-   * Creates a [Uint16List] with the same size as the [elements] list
+   * Creates a [Uint16List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Uint16List.fromList(List<int> elements);
@@ -534,7 +534,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Uint16List.view(ByteBuffer buffer,
                                    [int offsetInBytes = 0, int length]);
@@ -556,7 +556,7 @@
   external factory Int32List(int length);
 
   /**
-   * Creates a [Int32List] with the same size as the [elements] list
+   * Creates a [Int32List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Int32List.fromList(List<int> elements);
@@ -574,7 +574,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Int32List.view(ByteBuffer buffer,
                                   [int offsetInBytes = 0, int length]);
@@ -596,7 +596,7 @@
   external factory Uint32List(int length);
 
   /**
-   * Creates a [Uint32List] with the same size as the [elements] list
+   * Creates a [Uint32List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Uint32List.fromList(List<int> elements);
@@ -614,7 +614,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Uint32List.view(ByteBuffer buffer,
                                    [int offsetInBytes = 0, int length]);
@@ -636,7 +636,7 @@
   external factory Int64List(int length);
 
   /**
-   * Creates a [Int64List] with the same size as the [elements] list
+   * Creates a [Int64List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Int64List.fromList(List<int> elements);
@@ -654,7 +654,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Int64List.view(ByteBuffer buffer,
                                   [int offsetInBytes = 0, int length]);
@@ -676,7 +676,7 @@
   external factory Uint64List(int length);
 
   /**
-   * Creates a [Uint64List] with the same size as the [elements] list
+   * Creates a [Uint64List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Uint64List.fromList(List<int> elements);
@@ -695,7 +695,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Uint64List.view(ByteBuffer buffer,
                                    [int offsetInBytes = 0, int length]);
@@ -718,7 +718,7 @@
   external factory Float32List(int length);
 
   /**
-   * Creates a [Float32List] with the same size as the [elements] list
+   * Creates a [Float32List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Float32List.fromList(List<double> elements);
@@ -736,7 +736,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Float32List.view(ByteBuffer buffer,
                                     [int offsetInBytes = 0, int length]);
@@ -759,7 +759,7 @@
   external factory Float64List(int length);
 
   /**
-   * Creates a [Float64List] with the same size as the [elements] list
+   * Creates a [Float64List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Float64List.fromList(List<double> elements);
@@ -777,7 +777,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Float64List.view(ByteBuffer buffer,
                                     [int offsetInBytes = 0, int length]);
@@ -799,7 +799,7 @@
   external factory Float32x4List(int length);
 
   /**
-   * Creates a [Float32x4List] with the same size as the [elements] list
+   * Creates a [Float32x4List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Float32x4List.fromList(List<Float32x4> elements);
@@ -817,7 +817,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Float32x4List.view(ByteBuffer buffer,
                                       [int offsetInBytes = 0, int length]);
@@ -839,7 +839,7 @@
   external factory Int32x4List(int length);
 
   /**
-   * Creates a [Int32x4List] with the same size as the [elements] list
+   * Creates a [Int32x4List] with the same length as the [elements] list
    * and copies over the elements.
    */
   external factory Int32x4List.fromList(List<Int32x4> elements);
@@ -857,7 +857,7 @@
    * the length of [buffer].
    *
    * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
-   * BYTES_PER_ELEMENT.
+   * [BYTES_PER_ELEMENT].
    */
   external factory Int32x4List.view(ByteBuffer buffer,
                                       [int offsetInBytes = 0, int length]);
@@ -867,7 +867,47 @@
 
 
 /**
- * Interface of Dart Float32x4 immutable value type and operations.
+ * A fixed-length list of Float64x2 numbers that is viewable as a
+ * [TypedData]. For long lists, this implementation will be considerably more
+ * space- and time-efficient than the default [List] implementation.
+ */
+abstract class Float64x2List implements List<Float64x2>, TypedData {
+  /**
+   * Creates a [Float64x2List] of the specified length (in elements),
+   * all of whose elements have all lanes set to zero.
+   */
+  external factory Float64x2List(int length);
+
+  /**
+   * Creates a [Float64x2List] with the same length as the [elements] list
+   * and copies over the elements.
+   */
+  external factory Float64x2List.fromList(List<Float64x2> elements);
+
+  /**
+   * Creates a [Float64x2List] _view_ of the specified region in the specified
+   * byte buffer. Changes in the [Float64x2List] will be visible in the byte
+   * buffer and vice versa. If the [offsetInBytes] index of the region is not
+   * specified, it defaults to zero (the first byte in the byte buffer).
+   * If the length is not specified, it defaults to null, which indicates
+   * that the view extends to the end of the byte buffer.
+   *
+   * Throws [RangeError] if [offsetInBytes] or [length] are negative, or
+   * if [offsetInBytes] + ([length] * elementSizeInBytes) is greater than
+   * the length of [buffer].
+   *
+   * Throws [ArgumentError] if [offsetInBytes] is not a multiple of
+   * [BYTES_PER_ELEMENT].
+   */
+  external factory Float64x2List.view(ByteBuffer buffer,
+                                      [int offsetInBytes = 0, int length]);
+
+  static const int BYTES_PER_ELEMENT = 16;
+}
+
+
+/**
+ * Float32x4 immutable value type and operations.
  * Float32x4 stores 4 32-bit floating point values in "lanes".
  * The lanes are "x", "y", "z", and "w" respectively.
  */
@@ -876,6 +916,9 @@
   external factory Float32x4.splat(double v);
   external factory Float32x4.zero();
   external factory Float32x4.fromInt32x4Bits(Int32x4 x);
+  /// Sets the x and y lanes to their respective values in [v] and sets the z
+  /// and w lanes to 0.0.
+  external factory Float32x4.fromFloat64x2(Float64x2 v);
 
   /// Addition operator.
   Float32x4 operator+(Float32x4 other);
@@ -902,12 +945,12 @@
   Int32x4 notEqual(Float32x4 other);
 
   /// Returns a copy of [this] each lane being scaled by [s].
+  /// Equivalent to this * new Float32x4.splat(s)
   Float32x4 scale(double s);
-  /// Returns the absolute value of this [Float32x4].
+  /// Returns the lane-wise absolute value of this [Float32x4].
   Float32x4 abs();
-  /// Clamps [this] to be in the range [lowerLimit]-[upperLimit].
-  Float32x4 clamp(Float32x4 lowerLimit,
-                         Float32x4 upperLimit);
+  /// Lane-wise clamp [this] to be in the range [lowerLimit]-[upperLimit].
+  Float32x4 clamp(Float32x4 lowerLimit, Float32x4 upperLimit);
 
   /// Extracted x value.
   double get x;
@@ -919,6 +962,10 @@
   double get w;
 
   /// Extract the sign bits from each lane return them in the first 4 bits.
+  /// "x" lane is bit 0.
+  /// "y" lane is bit 1.
+  /// "z" lane is bit 2.
+  /// "w" lane is bit 3.
   int get signMask;
 
   /// Mask passed to [shuffle] or [shuffleMix].
@@ -1214,7 +1261,7 @@
 
 
 /**
- * Interface of Dart Int32x4 and operations.
+ * Int32x4 and operations.
  * Int32x4 stores 4 32-bit bit-masks in "lanes".
  * The lanes are "x", "y", "z", and "w" respectively.
  */
@@ -1244,6 +1291,10 @@
   int get w;
 
   /// Extract the top bit from each lane return them in the first 4 bits.
+  /// "x" lane is bit 0.
+  /// "y" lane is bit 1.
+  /// "z" lane is bit 2.
+  /// "w" lane is bit 3.
   int get signMask;
 
   /// Mask passed to [shuffle] or [shuffleMix].
@@ -1544,3 +1595,61 @@
   /// Select bit from [falseValue] when bit in [this] is off.
   Float32x4 select(Float32x4 trueValue, Float32x4 falseValue);
 }
+
+/**
+ * Float64x2 immutable value type and operations.
+ * Float64x2 stores 2 64-bit floating point values in "lanes".
+ * The lanes are "x" and "y" respectively.
+ */
+abstract class Float64x2 {
+  external factory Float64x2(double x, double y);
+  external factory Float64x2.splat(double v);
+  external factory Float64x2.zero();
+  /// Uses the "x" and "y" lanes from [v].
+  external factory Float64x2.fromFloat32x4(Float32x4 v);
+
+  /// Addition operator.
+  Float64x2 operator+(Float64x2 other);
+  /// Negate operator.
+  Float64x2 operator-();
+  /// Subtraction operator.
+  Float64x2 operator-(Float64x2 other);
+  /// Multiplication operator.
+  Float64x2 operator*(Float64x2 other);
+  /// Division operator.
+  Float64x2 operator/(Float64x2 other);
+
+  /// Returns a copy of [this] each lane being scaled by [s].
+  /// Equivalent to this * new Float64x2.splat(s)
+  Float64x2 scale(double s);
+  /// Returns the lane-wise absolute value of this [Float64x2].
+  Float64x2 abs();
+
+  /// Lane-wise clamp [this] to be in the range [lowerLimit]-[upperLimit].
+  Float64x2 clamp(Float64x2 lowerLimit,
+                  Float64x2 upperLimit);
+
+  /// Extracted x value.
+  double get x;
+  /// Extracted y value.
+  double get y;
+
+  /// Extract the sign bits from each lane return them in the first 2 bits.
+  /// "x" lane is bit 0.
+  /// "y" lane is bit 1.
+  int get signMask;
+
+  /// Returns a new [Float64x2] copied from [this] with a new x value.
+  Float64x2 withX(double x);
+  /// Returns a new [Float64x2] copied from [this] with a new y value.
+  Float64x2 withY(double y);
+
+  /// Returns the lane-wise minimum value in [this] or [other].
+  Float64x2 min(Float64x2 other);
+
+  /// Returns the lane-wise maximum value in [this] or [other].
+  Float64x2 max(Float64x2 other);
+
+  /// Returns the lane-wise square root of [this].
+  Float64x2 sqrt();
+}
diff --git a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
index 185ac73..561e1f0 100644
--- a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
+++ b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -3158,14 +3158,14 @@
    */
   @JSName('texSubImage2D')
   void texSubImage2DUntyped(int targetTexture, int levelOfDetail,
-      int internalFormat, int format, int type, data) native;
+      int xOffset, int yOffset, int format, int type, data) native;
 
   /**
    * Updates a sub-rectangle of the currently bound texture to [data].
    */
   @JSName('texSubImage2D')
   void texSubImage2DTyped(int targetTexture, int levelOfDetail,
-      int internalFormat, int width, int height, int border, int format,
+      int xOffset, int yOffset, int width, int height, int border, int format,
       int type, TypedData data) native;
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
diff --git a/sdk/lib/web_gl/dartium/web_gl_dartium.dart b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
index e19200f..867aa67 100644
--- a/sdk/lib/web_gl/dartium/web_gl_dartium.dart
+++ b/sdk/lib/web_gl/dartium/web_gl_dartium.dart
@@ -2990,8 +2990,8 @@
    *
    */
   void texSubImage2DUntyped(int targetTexture, int levelOfDetail, 
-      int internalFormat, int format, int type, data) {
-    texSubImage2D(targetTexture, levelOfDetail, internalFormat,
+      int xOffset, int yOffset, int format, int type, data) {
+    texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset,
         format, type, data);
   }
 
@@ -2999,10 +2999,10 @@
    * Updates a sub-rectangle of the currently bound texture to [data].
    */
   void texSubImage2DTyped(int targetTexture, int levelOfDetail,
-      int internalFormat, int width, int height, int border, int format,
+      int xOffset, int yOffset, int width, int height, int format,
       int type, TypedData data) {
-    texSubImage2D(targetTexture, levelOfDetail, internalFormat,
-        width, height, border, format, type, data);
+    texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset,
+        width, height, format, type, data);
   }
 }
 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
diff --git a/site/try/build_try.gyp b/site/try/build_try.gyp
index 1122ba0..193cc13 100644
--- a/site/try/build_try.gyp
+++ b/site/try/build_try.gyp
@@ -26,7 +26,7 @@
           '../../third_party/font-awesome/font-awesome-4.0.3/'
           'fonts/fontawesome-webfont.woff',
 
-          '../../sdk/lib/_internal/dartdoc/static/favicon.ico',
+          'favicon.ico',
 
           '<(SHARED_INTERMEDIATE_DIR)/leap.dart.js',
           '<(SHARED_INTERMEDIATE_DIR)/sdk.json',
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 597905e..beab79d 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -490,7 +490,6 @@
 LibTest/typed_data/Float32List/fold_A01_t01: fail # co19-roll r559: Please triage this failure
 LibTest/typed_data/Float32List/join_A01_t01: fail # co19-roll r559: Please triage this failure
 LibTest/typed_data/Float32List/join_A01_t02: fail # co19-roll r559: Please triage this failure
-LibTest/typed_data/Float32x4List/Float32x4List.view_A02_t01: RuntimeError # co19-roll r559: Please triage this failure
 LibTest/typed_data/Float32x4List/Float32x4List.view_A05_t01: RuntimeError # co19-roll r559: Please triage this failure
 LibTest/typed_data/Float32x4List/Float32x4List.view_A05_t02: RuntimeError # co19-roll r559: Please triage this failure
 LibTest/typed_data/Float32x4List/Float32x4List.view_A05_t03: RuntimeError # co19-roll r559: Please triage this failure
@@ -574,7 +573,6 @@
 LibTest/async/Stream/Stream.periodic_A02_t01: fail # co19-roll r546: Please triage this failure
 LibTest/async/Timer/cancel_A01_t01: fail # co19-roll r546: Please triage this failure
 LibTest/async/Timer/Timer_A01_t01: fail # co19-roll r546: Please triage this failure
-LibTest/typed_data/Float32x4List/Float32x4List.view_A01_t02: fail # co19-roll r587: Please triage this failure
 LibTest/typed_data/Float32x4List/Float32x4List.view_A06_t01: fail # co19-roll r587: Please triage this failure
 Language/12_Expressions/00_Object_Identity/1_Object_Identity_A05_t02: RuntimeError # co19-roll r607: Please triage this failure
 Language/12_Expressions/17_Getter_Invocation_A07_t02: RuntimeError # co19-roll r607: Please triage this failure
diff --git a/tests/co19/co19-dartium.status b/tests/co19/co19-dartium.status
index a1f2845..ad284aa 100644
--- a/tests/co19/co19-dartium.status
+++ b/tests/co19/co19-dartium.status
@@ -5,7 +5,7 @@
 [ $compiler == none && $runtime == drt ]
 *: Skip # running co19 tests on content_shell would make our dartium cycle-times very long
 
-[ $compiler == none && $runtime == dartium && $mode == debug && $system == windows ]
+[ $compiler == none && $runtime == dartium && $mode == debug ]
 Language/15_Types/4_Interface_Types_A11_t01: Skip # Issue 16343
 Language/15_Types/4_Interface_Types_A11_t02: Skip # Issue 16343
 
@@ -39,5 +39,7 @@
 LibTest/isolate/Isolate/spawn_A01_t04: RuntimeError # co19-roll r667: Please triage this failure
 LibTest/isolate/Isolate/spawn_A01_t05: RuntimeError # co19-roll r667: Please triage this failure
 
+LibTest/async/Timer/Timer_A01_t01: RuntimeError, Pass # Issue 16475
+
 [ $compiler == none && $runtime == dartium && $checked ]
 LibTest/core/List/removeAt_A02_t01: Fail # co19-roll r641: Please triage this failure
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index d601c2c..763bf35 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -83,16 +83,21 @@
   return backend.assembleCode(element);
 }
 
+// TODO(herhut): Disallow warnings and errors during compilation by default.
 MockCompiler compilerFor(String code, Uri uri,
                          {bool analyzeAll: false,
                           bool analyzeOnly: false,
                           String coreSource: DEFAULT_CORELIB,
-                          bool disableInlining: true}) {
+                          bool disableInlining: true,
+                          bool allowErrors: true,
+                          bool allowWarnings: true}) {
   MockCompiler compiler = new MockCompiler(
       analyzeAll: analyzeAll,
       analyzeOnly: analyzeOnly,
       coreSource: coreSource,
-      disableInlining: disableInlining);
+      disableInlining: disableInlining,
+      allowErrors: allowErrors,
+      allowWarnings: allowWarnings);
   compiler.sourceFiles[uri.toString()] =
       new StringSourceFile(uri.toString(), code);
   return compiler;
@@ -100,10 +105,13 @@
 
 Future<String> compileAll(String code,
                           {String coreSource: DEFAULT_CORELIB,
-                          bool disableInlining: true}) {
+                          bool disableInlining: true,
+                          bool allowErrors: true,
+                          bool allowWarnings: true}) {
   Uri uri = new Uri(scheme: 'source');
   MockCompiler compiler = compilerFor(
-      code, uri, coreSource: coreSource, disableInlining: disableInlining);
+      code, uri, coreSource: coreSource, disableInlining: disableInlining,
+      allowErrors: allowErrors, allowWarnings: allowWarnings);
   return compiler.runCompiler(uri).then((_) {
     Expect.isFalse(compiler.compilationFailed,
                    'Unexpected compilation error');
@@ -113,9 +121,12 @@
 
 Future compileAndCheck(String code,
                        String name,
-                       check(MockCompiler compiler, lego.Element element)) {
+                       check(MockCompiler compiler, lego.Element element),
+                       {bool allowErrors: true, bool allowWarnings: true}) {
   Uri uri = new Uri(scheme: 'source');
-  MockCompiler compiler = compilerFor(code, uri);
+  MockCompiler compiler = compilerFor(code, uri,
+                                      allowErrors: allowErrors,
+                                      allowWarnings: allowWarnings);
   return compiler.runCompiler(uri).then((_) {
     lego.Element element = findElement(compiler, name);
     return check(compiler, element);
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index 7bbae64..90ce342 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -6,17 +6,31 @@
 constant_folding_string_test: Fail
 boolified_operator_test: Fail # Issue 8001
 
-# Don't mark these tests as failing. Instead, fix the errors/warnings that they
-# report or update the whitelist in the test-files to temporarily allow
-# digression.
-analyze_api_test: Pass, Slow # DON'T CHANGE THIS LINE -- SEE ABOVE.
-analyze_dart2js_test: Pass, Slow # DON'T CHANGE THIS LINE -- SEE ABOVE.
-
 # simple_function_subtype_test is temporarily(?) disabled due to new method for
 # building function type tests.
 simple_function_subtype_test: Fail
 
 mirror_final_field_inferrer2_test: Crash, Pass # dartbug.com/15581
 
+simple_inferrer_const_closure_test: Fail # Issue 16507
+simple_inferrer_const_closure2_test: Fail # Issue 16507
+simple_inferrer_global_field_closure_test: Fail # Issue 16507
+
+[ $mode == debug ]
+mirror_final_field_inferrer2_test: Crash, Pass, Slow # dartbug.com/15581
+
+deferred_mirrors_test: Pass, Slow
+in_user_code_test: Pass, Slow
+analyze_unused_dart2js_test: Pass, Slow
+exit_code_test: Pass, Slow
+deferred_load_graph_segmentation_test: Pass, Slow
+check_members_test: Pass, Slow
+
+# Don't mark these tests as failing. Instead, fix the errors/warnings that they
+# report or update the whitelist in the test-files to temporarily allow
+# digression.
+analyze_api_test: Pass, Slow # DON'T CHANGE THIS LINE -- SEE ABOVE.
+analyze_dart2js_test: Pass, Slow # DON'T CHANGE THIS LINE -- SEE ABOVE.
+
 [ $jscl || $runtime == drt || $runtime == dartium || $runtime == ff || $runtime == firefox || $runtime == chrome || $runtime == safari || $runtime == ie9 || $runtime == opera ]
 *: Skip # dart2js uses #import('dart:io'); and it is not self-hosted (yet).
diff --git a/tests/compiler/dart2js/deferred_emit_type_checks_test.dart b/tests/compiler/dart2js/deferred_emit_type_checks_test.dart
new file mode 100644
index 0000000..890397a
--- /dev/null
+++ b/tests/compiler/dart2js/deferred_emit_type_checks_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2014, 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.
+
+// Test that the additional runtime type support is output to the right
+// Files when using deferred loading.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'memory_source_file_helper.dart';
+import "dart:async";
+
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+       as dart2js;
+
+class MemoryOutputSink<T> extends EventSink<T> {
+  List<T> mem = new List<T>();
+  void add(T event) {
+    mem.add(event);
+  }
+  void addError(T event, [StackTrace stackTrace]) {}
+  void close() {}
+}
+
+void main() {
+  Uri script = currentDirectory.resolveUri(Platform.script);
+  Uri libraryRoot = script.resolve('../../../sdk/');
+  Uri packageRoot = script.resolve('./packages/');
+
+  var provider = new MemorySourceFileProvider(MEMORY_SOURCE_FILES);
+  var handler = new FormattingDiagnosticHandler(provider);
+
+  Map<String, MemoryOutputSink> outputs = new Map<String, MemoryOutputSink>();
+
+  MemoryOutputSink outputSaver(name, extension) {
+    if (name == '') {
+      name = 'main';
+      extension ='js';
+    }
+    return outputs.putIfAbsent("$name.$extension", () {
+     return new MemoryOutputSink();
+    });
+  }
+
+  Compiler compiler = new Compiler(provider.readStringFromUri,
+                                   outputSaver,
+                                   handler.diagnosticHandler,
+                                   libraryRoot,
+                                   packageRoot,
+                                   [],
+                                   {});
+  asyncTest(() => compiler.run(Uri.parse('memory:main.dart')).then((_) {
+    String mainOutput = outputs['main.js'].mem[0];
+    String deferredOutput = outputs['deferred.js'].mem[0];
+    RegExp re = new RegExp(r"\n.\.A\.\$isA = true;");
+    print(deferredOutput);
+    Expect.isTrue(re.hasMatch(deferredOutput));
+    Expect.isFalse(re.hasMatch(mainOutput));
+  }));
+}
+
+// We force additional runtime type support to be output for A by instantiating
+// it with a type argument, and testing for the type. The extra support should
+// go to the deferred hunk.
+const Map MEMORY_SOURCE_FILES = const {"main.dart": """
+import "dart:async";
+
+@def import 'lib.dart' show f, A;
+
+const def = const DeferredLibrary("deferred");
+
+void main() {
+  def.load().then((_) {
+    print(f(new A<A>()));
+  });
+}
+""", "lib.dart": """
+class A<T> {}
+
+bool f (Object o) {
+  return o is A<A>;
+}
+""",};
diff --git a/tests/compiler/dart2js/list_tracer_test.dart b/tests/compiler/dart2js/list_tracer_test.dart
index 738c48c..e2e8d82 100644
--- a/tests/compiler/dart2js/list_tracer_test.dart
+++ b/tests/compiler/dart2js/list_tracer_test.dart
@@ -117,7 +117,7 @@
   ((a) => a[0] = aDouble)(listPassedToClosure);
 
   listReturnedFromClosure[0] = anInt;
-  (() => listReturnedFromClosure)[0] = aDouble;
+  (() => listReturnedFromClosure)()[0] = aDouble;
 
   listInField[0] = anInt;
   new A(listInField).useField();
@@ -198,7 +198,8 @@
 
 void doTest(String allocation, {bool nullify}) {
   Uri uri = new Uri(scheme: 'source');
-  var compiler = compilerFor(generateTest(allocation), uri);
+  var compiler = compilerFor(generateTest(allocation), uri,
+                             allowErrors: false, allowWarnings: false);
   asyncTest(() => compiler.runCompiler(uri).then((_) {
     var typesTask = compiler.typesTask;
     var typesInferrer = typesTask.typesInferrer;
diff --git a/tests/compiler/dart2js/map_tracer_test.dart b/tests/compiler/dart2js/map_tracer_test.dart
new file mode 100644
index 0000000..8dc4fcd
--- /dev/null
+++ b/tests/compiler/dart2js/map_tracer_test.dart
@@ -0,0 +1,283 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import
+    '../../../sdk/lib/_internal/compiler/implementation/types/types.dart'
+    show MapTypeMask, TypeMask;
+
+import 'compiler_helper.dart';
+import 'parser_helper.dart';
+
+
+String generateTest(String mapAllocation) {
+  return """
+int anInt = 42;
+double aDouble = 42.5;
+String aKey = 'aKey';
+String anotherKey = 'anotherKey';
+String presetKey = 'presetKey';
+
+class A {
+  var field;
+  var nonFinalField;
+
+  A(this.field);
+
+  A.bar(map) {
+    nonFinalField = map;
+  }
+
+  receiveIt(map) {
+    map[aKey] = aDouble;
+  }
+
+  returnIt() {
+    return mapReturnedFromSelector;
+  }
+
+  useField() {
+    field[aKey] = aDouble;
+  }
+
+  set callSetter(map) {
+    map[aKey] = aDouble;
+  }
+
+  operator[](key) {
+    key[aKey] = aDouble;
+  }
+
+  operator[]=(index, value) {
+    index[aKey] = anInt;
+    if (value == mapEscapingTwiceInIndexSet) {
+      value[aKey] = aDouble;
+    }
+  }
+}
+
+class B extends A {
+  B(map) : super.bar(map);
+
+  set nonFinalField(value) {
+    value[aKey] = aDouble;
+  }
+}
+
+class C {
+  C();
+
+  operator[]=(index, value) {
+    index[aKey] = anInt;
+    value[aKey] = aDouble;
+  }
+}
+
+var mapInField = $mapAllocation;
+var mapPassedToClosure = $mapAllocation;
+var mapReturnedFromClosure = $mapAllocation;
+var mapPassedToMethod = $mapAllocation;
+var mapReturnedFromMethod = $mapAllocation;
+var mapUsedWithCascade = $mapAllocation;
+var mapUsedInClosure = $mapAllocation;
+var mapPassedToSelector = $mapAllocation;
+var mapReturnedFromSelector = $mapAllocation;
+var mapUsedWithNonOkSelector = $mapAllocation;
+var mapUsedWithConstraint = $mapAllocation;
+var mapEscapingFromSetter = $mapAllocation;
+var mapUsedInLocal = $mapAllocation;
+var mapUnset = $mapAllocation;
+var mapOnlySetWithConstraint = $mapAllocation;
+var mapEscapingInSetterValue = $mapAllocation;
+var mapEscapingInIndex = $mapAllocation;
+var mapEscapingInIndexSet = $mapAllocation;
+var mapEscapingTwiceInIndexSet = $mapAllocation;
+var mapPassedAsOptionalParameter = $mapAllocation;
+var mapPassedAsNamedParameter = $mapAllocation;
+var mapSetInNonFinalField = $mapAllocation;
+var mapStoredInList = $mapAllocation;
+var mapStoredInListButEscapes = $mapAllocation;
+var mapStoredInMap = $mapAllocation;
+var mapStoredInMapButEscapes = $mapAllocation;
+
+foo(map) {
+  map[aKey] = aDouble;
+}
+
+bar() {
+  return mapReturnedFromMethod;
+}
+
+takeOptional([map]) {
+  map[aKey] = aDouble;
+}
+
+takeNamed({map}) {
+  map[aKey] = aDouble;
+}
+
+main() {
+  mapReturnedFromMethod[aKey] = anInt;
+  bar()[aKey] = aDouble;
+
+  mapPassedToMethod[aKey] = anInt;
+  foo(mapPassedToMethod);
+
+  mapPassedToClosure[aKey] = anInt;
+  ((a) => a[aKey] = aDouble)(mapPassedToClosure);
+
+  mapReturnedFromClosure[aKey] = anInt;
+  (() => mapReturnedFromClosure)()[aKey] = aDouble;
+
+  mapInField[aKey] = anInt;
+  new A(mapInField).useField();
+
+  mapUsedWithCascade[aKey] = anInt;
+  mapUsedWithCascade..[aKey] = aDouble;
+
+  mapUsedInClosure[aKey] = anInt;
+  (() => mapUsedInClosure[aKey] = aDouble)();
+
+  mapPassedToSelector[aKey] = anInt;
+  new A(null).receiveIt(mapPassedToSelector);
+
+  mapReturnedFromSelector[aKey] = anInt;
+  new A(null).returnIt()[aKey] = aDouble;
+
+  mapUsedWithNonOkSelector[aKey] = anInt;
+  mapUsedWithNonOkSelector.map((k,v) => v);
+
+  mapUsedWithConstraint[aKey] = anInt;
+  mapUsedWithConstraint[aKey]++;
+  mapUsedWithConstraint[aKey] += anInt;
+
+  mapEscapingFromSetter[aKey] = anInt;
+  foo(new A(null).field = mapEscapingFromSetter);
+
+  mapUsedInLocal[aKey] = anInt;
+  var a = mapUsedInLocal;
+  mapUsedInLocal[anotherKey] = aDouble;
+
+  // At least use [mapUnset] in a local to pretend it's used.
+  var b = mapUnset;
+
+  mapOnlySetWithConstraint[aKey]++;
+
+  mapEscapingInSetterValue[aKey] = anInt;
+  new A(null).callSetter = mapEscapingInSetterValue;
+
+  mapEscapingInIndex[aKey] = anInt;
+  new A(null)[mapEscapingInIndex];
+
+  new A(null)[mapEscapingInIndexSet] = 42;
+
+  new C()[mapEscapingTwiceInIndexSet] = mapEscapingTwiceInIndexSet;
+
+  mapPassedAsOptionalParameter[aKey] = anInt;
+  takeOptional(mapPassedAsOptionalParameter);
+
+  mapPassedAsNamedParameter[aKey] = anInt;
+  takeNamed(map: mapPassedAsNamedParameter);
+
+  mapSetInNonFinalField[aKey] = anInt;
+  new B(mapSetInNonFinalField);
+
+  a = [mapStoredInList];
+  a[0][aKey] = 42;
+
+  a = [mapStoredInListButEscapes];
+  a[0][aKey] = 42;
+  a.forEach((e) => print(e));
+
+  a = {aKey: mapStoredInMap};
+  a[aKey][aKey] = 42;
+
+  a = {aKey: mapStoredInMapButEscapes};
+  a[aKey][aKey] = 42;
+  a.forEach((k,v) => print(v));
+}
+""";
+}
+
+void main() {
+  // Test empty literal map
+  doTest('{}');
+  // Test preset map of <String,uint32>
+  doTest('{presetKey : anInt}', "presetKey", "anInt");
+  // Test preset map of <Double,uint32>
+  doTest('{aDouble : anInt}', "aDouble", "anInt");
+}
+
+void doTest(String allocation, [String keyElement,
+            String valueElement]) {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(generateTest(allocation), uri,
+                             allowErrors: false, allowWarnings: false);
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var keyType, valueType;
+    var typesTask = compiler.typesTask;
+    var typesInferrer = typesTask.typesInferrer;
+    var emptyType = new TypeMask.nonNullEmpty();
+    var aKeyType
+      = typesInferrer.getTypeOfElement(findElement(compiler, 'aKey'));
+    if (keyElement != null) {
+      keyType
+        = typesInferrer.getTypeOfElement(findElement(compiler, keyElement));
+    }
+    if (valueElement != null) {
+      valueType
+        = typesInferrer.getTypeOfElement(findElement(compiler, valueElement));
+    }
+    if (keyType == null) keyType = emptyType;
+    if (valueType == null) valueType = emptyType;
+
+    checkType(String name, keyType, valueType) {
+      var element = findElement(compiler, name);
+      MapTypeMask mask = typesInferrer.getTypeOfElement(element);
+      Expect.equals(keyType, mask.keyType.simplify(compiler), name);
+      Expect.equals(valueType, mask.valueType.simplify(compiler), name);
+    }
+
+    K(TypeMask other) => keyType.union(other, compiler).simplify(compiler);
+    V(TypeMask other) => valueType.union(other, compiler).simplify(compiler);
+
+    checkType('mapInField', K(aKeyType), V(typesTask.numType));
+    checkType('mapPassedToMethod', K(aKeyType), V(typesTask.numType));
+    checkType('mapReturnedFromMethod', K(aKeyType), V(typesTask.numType));
+    checkType('mapUsedWithCascade', K(aKeyType), V(typesTask.numType));
+    checkType('mapUsedInClosure', K(aKeyType), V(typesTask.numType));
+    checkType('mapPassedToSelector', K(aKeyType), V(typesTask.numType));
+    checkType('mapReturnedFromSelector', K(aKeyType), V(typesTask.numType));
+    checkType('mapUsedWithConstraint', K(aKeyType), V(typesTask.uint31Type));
+    checkType('mapEscapingFromSetter', K(aKeyType), V(typesTask.numType));
+    checkType('mapUsedInLocal', K(aKeyType), V(typesTask.numType));
+    checkType('mapEscapingInSetterValue', K(aKeyType), V(typesTask.numType));
+    checkType('mapEscapingInIndex', K(aKeyType), V(typesTask.numType));
+    checkType('mapEscapingInIndexSet', K(aKeyType), V(typesTask.uint31Type));
+    checkType('mapEscapingTwiceInIndexSet', K(aKeyType), V(typesTask.numType));
+    checkType('mapSetInNonFinalField', K(aKeyType), V(typesTask.numType));
+
+    checkType('mapPassedToClosure', K(typesTask.dynamicType),
+                                    V(typesTask.dynamicType));
+    checkType('mapReturnedFromClosure', K(typesTask.dynamicType),
+                                        V(typesTask.dynamicType));
+    checkType('mapUsedWithNonOkSelector', K(typesTask.dynamicType),
+                                          V(typesTask.dynamicType));
+    checkType('mapPassedAsOptionalParameter', K(aKeyType),
+                                              V(typesTask.numType));
+    checkType('mapPassedAsNamedParameter', K(aKeyType),
+                                           V(typesTask.numType));
+    checkType('mapStoredInList', K(aKeyType),
+                                 V(typesTask.uint31Type));
+    checkType('mapStoredInListButEscapes', K(typesTask.dynamicType),
+                                           V(typesTask.dynamicType));
+    checkType('mapStoredInMap', K(aKeyType), V(typesTask.uint31Type));
+    checkType('mapStoredInMapButEscapes', K(typesTask.dynamicType),
+                                          V(typesTask.dynamicType));
+
+    checkType('mapUnset', K(emptyType), V(emptyType));
+    checkType('mapOnlySetWithConstraint', K(aKeyType), V(emptyType));
+  }));
+}
diff --git a/tests/compiler/dart2js/memory_compiler.dart b/tests/compiler/dart2js/memory_compiler.dart
index f39e046..269cc1c 100644
--- a/tests/compiler/dart2js/memory_compiler.dart
+++ b/tests/compiler/dart2js/memory_compiler.dart
@@ -15,8 +15,8 @@
 
 import 'dart:async';
 
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart';
 
 class DiagnosticMessage {
   final Uri uri;
@@ -83,11 +83,10 @@
                       Compiler cachedCompiler,
                       bool showDiagnostics: true,
                       Uri packageRoot}) {
-  Uri script = currentDirectory.resolveUri(Platform.script);
-  Uri libraryRoot = script.resolve('../../../sdk/');
+  Uri libraryRoot = Uri.base.resolve('sdk/');
+  Uri script = Uri.base.resolveUri(Platform.script);
   if (packageRoot == null) {
-    packageRoot = currentDirectory.resolve(
-        appendSlash(nativeToUriPath(Platform.packageRoot)));
+    packageRoot = Uri.base.resolve('${Platform.packageRoot}/');
   }
 
   MemorySourceFileProvider provider;
@@ -158,9 +157,9 @@
                                      {DiagnosticHandler diagnosticHandler,
                                       List<String> options: const [],
                                       bool showDiagnostics: true}) {
-  Uri script = currentDirectory.resolveUri(Platform.script);
-  Uri libraryRoot = script.resolve('../../../sdk/');
-  Uri packageRoot = script.resolve('./packages/');
+  Uri libraryRoot = Uri.base.resolve('sdk/');
+  Uri packageRoot = Uri.base.resolve('${Platform.packageRoot}/');
+  Uri script = Uri.base.resolveUri(Platform.script);
 
   var provider = new MemorySourceFileProvider(memorySourceFiles);
   var handler =
diff --git a/tests/compiler/dart2js/mirror_system_helper.dart b/tests/compiler/dart2js/mirror_system_helper.dart
index 2776de6..3faf23d 100644
--- a/tests/compiler/dart2js/mirror_system_helper.dart
+++ b/tests/compiler/dart2js/mirror_system_helper.dart
@@ -5,11 +5,11 @@
 library mirror_system_helper;

 

 import 'dart:async';

-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';

-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';

+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';

+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart';

 import 'mock_compiler.dart';

 

-export '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';

+export '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';

 export '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';

 

 const String SOURCE = 'source';

diff --git a/tests/compiler/dart2js/mirrors/class_mirror_type_variables_test.dart b/tests/compiler/dart2js/mirrors/class_mirror_type_variables_test.dart
new file mode 100644
index 0000000..a3f6871
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors/class_mirror_type_variables_test.dart
@@ -0,0 +1,42 @@
+// 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.

+

+import "dart:mirrors";

+

+import "package:async_helper/async_helper.dart";

+

+import "mirrors_test_helper.dart";

+import "../../../lib/mirrors/class_mirror_type_variables_expect.dart";

+

+class CompileTimeEnv implements Env {

+  final MirrorSystem mirrors;

+

+  CompileTimeEnv(this.mirrors);

+

+  LibraryMirror get core => mirrors.libraries[Uri.parse('dart:core')];

+

+  LibraryMirror get test =>

+      mirrors.findLibrary(#class_mirror_type_variables_data);

+

+

+  ClassMirror getA() => test.declarations[#A];

+  ClassMirror getB() => test.declarations[#B];

+  ClassMirror getC() => test.declarations[#C];

+  ClassMirror getD() => test.declarations[#D];

+  ClassMirror getE() => test.declarations[#E];

+  ClassMirror getF() => test.declarations[#F];

+  ClassMirror getNoTypeParams() => test.declarations[#NoTypeParams];

+  ClassMirror getObject() => core.declarations[#Object];

+  ClassMirror getString() => core.declarations[#String];

+  ClassMirror getHelperOfString() =>

+      createInstantiation(test.declarations[#Helper], [getString()]);

+}

+

+main() {

+  asyncTest(() => analyze("class_mirror_type_variables_data.dart").

+      then((MirrorSystem mirrors) {

+    test(new CompileTimeEnv(mirrors));

+  }));

+

+}

diff --git a/tests/compiler/dart2js/mirrors/default_value_test.dart b/tests/compiler/dart2js/mirrors/default_value_test.dart
new file mode 100644
index 0000000..53b8721
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors/default_value_test.dart
@@ -0,0 +1,62 @@
+// 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.

+

+import "dart:mirrors";

+

+import "package:async_helper/async_helper.dart";

+import "package:expect/expect.dart";

+import "../memory_compiler.dart";

+

+const SOURCE = const {

+  'main.dart': """

+library main;

+

+class Class {

+  var a, b, c, d, e, f, g, h;

+  Class.optional(this.a, int b, void this.c(), 

+                 [this.d, int this.e, void this.f(), 

+                  this.g = 0, int this.h = 0]);

+  Class.named(this.a, int b, void this.c(), 

+                 {this.d, int this.e, void this.f(), 

+                  this.g: 0, int this.h: 0});

+  methodOptional(a, int b, void c(), 

+                 [d, int e, void f(), 

+                  g = 0, int h = 0]) {}

+  methodNamed(a, int b, void c(), 

+              {d, int e, void f(), 

+               g: 0, int h: 0}) {}

+} 

+""",

+};

+

+main() {

+  asyncTest(() => mirrorSystemFor(SOURCE).then((MirrorSystem mirrors) {

+    LibraryMirror dartCore = mirrors.libraries[Uri.parse('memory:main.dart')];

+    ClassMirror classMirror = dartCore.declarations[#Class];

+    testMethod(classMirror.declarations[#optional]);

+    testMethod(classMirror.declarations[#named]);

+    testMethod(classMirror.declarations[#methodOptional]);

+    testMethod(classMirror.declarations[#methodNamed]);

+  }));

+}

+

+testMethod(MethodMirror mirror) {

+  Expect.equals(8, mirror.parameters.length);

+  for (int i = 0 ; i < 6 ; i++) {

+    testParameter(mirror.parameters[i], false);

+  }

+  for (int i = 6 ; i < 8 ; i++) {

+    testParameter(mirror.parameters[i], true);

+  }

+}

+

+testParameter(ParameterMirror mirror, bool expectDefaultValue) {

+  if (expectDefaultValue) {

+    Expect.isTrue(mirror.hasDefaultValue);

+    Expect.isNotNull(mirror.defaultValue);

+  } else {

+    Expect.isFalse(mirror.hasDefaultValue);

+    Expect.isNull(mirror.defaultValue);

+  }

+}

diff --git a/tests/compiler/dart2js/mirrors/mirrors_reader_test.dart b/tests/compiler/dart2js/mirrors/mirrors_reader_test.dart
new file mode 100644
index 0000000..53c9ceb
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors/mirrors_reader_test.dart
@@ -0,0 +1,141 @@
+// 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.

+

+// Test that everything reachable from a [MirrorSystem] can be accessed.

+

+library test.mirrors.reader;

+

+import "dart:mirrors" hide SourceLocation;

+

+import "package:async_helper/async_helper.dart";

+

+import "mirrors_test_helper.dart";

+import "../../../lib/mirrors/mirrors_reader.dart";

+import "../../../../sdk/lib/_internal/compiler/implementation/util/util.dart";

+import "../../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirrors.dart";

+import "../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart";

+

+class SourceMirrorsReader extends MirrorsReader {

+  final Dart2JsMirrorSystem mirrorSystem;

+

+  SourceMirrorsReader(this.mirrorSystem,

+                      {bool verbose: false, bool includeStackTrace: false})

+      : super(verbose: verbose, includeStackTrace: includeStackTrace);

+

+  evaluate(f()) {

+    try {

+      return f();

+    } on SpannableAssertionFailure catch (e) {

+      mirrorSystem.compiler.reportAssertionFailure(e);

+      rethrow;

+    }

+  }

+

+  visitMirror(Mirror mirror) {

+    if (mirror is CombinatorMirror) {

+      visitCombinatorMirror(mirror);

+    } else if (mirror is LibraryDependencyMirror) {

+      visitLibraryDependencyMirror(mirror);

+    } else if (mirror is CommentInstanceMirror) {

+      visitCommentInstanceMirror(mirror);

+    } else if (mirror is ListInstanceMirror) {

+      visitListInstanceMirror(mirror);

+    } else if (mirror is MapInstanceMirror) {

+      visitMapInstanceMirror(mirror);

+    } else if (mirror is TypeInstanceMirror) {

+      visitTypeInstanceMirror(mirror);

+    } else {

+      super.visitMirror(mirror);

+    }

+  }

+

+  visitDeclarationMirror(DeclarationSourceMirror mirror) {

+    super.visitDeclarationMirror(mirror);

+    visit(mirror, 'isNameSynthetic', () => mirror.isNameSynthetic);

+  }

+

+  visitClassMirror(ClassSourceMirror mirror) {

+    super.visitClassMirror(mirror);

+    visit(mirror, 'isAbstract', () => mirror.isAbstract);

+  }

+

+  visitLibraryMirror(LibrarySourceMirror mirror) {

+    super.visitLibraryMirror(mirror);

+    visit(mirror, 'libraryDependencies', () => mirror.libraryDependencies);

+  }

+

+  visitParameterMirror(ParameterMirror mirror) {

+    super.visitParameterMirror(mirror);

+    if (mirror is ParameterSourceMirror) {

+      visit(mirror, 'isInitializingFormal', () => mirror.isInitializingFormal);

+      visit(mirror, 'initializedField', () => mirror.initializedField);

+    }

+  }

+

+  visitTypeMirror(TypeSourceMirror mirror) {

+    super.visitTypeMirror(mirror);

+    visit(mirror, 'isVoid', () => mirror.isVoid);

+    visit(mirror, 'isDynamic', () => mirror.isDynamic);

+  }

+

+  visitSourceLocation(SourceLocation location) {

+    super.visitSourceLocation(location);

+    visit(location, 'line', () => location.line);

+    visit(location, 'column', () => location.column);

+    visit(location, 'offset', () => location.offset);

+    visit(location, 'length', () => location.length);

+    visit(location, 'text', () => location.text);

+    visit(location, 'sourceUri', () => location.sourceUri);

+    visit(location, 'sourceText', () => location.sourceText);

+  }

+

+  visitCombinatorMirror(CombinatorMirror mirror) {

+    visit(mirror, 'identifiers', () => mirror.identifiers);

+    visit(mirror, 'isShow', () => mirror.isShow);

+    visit(mirror, 'isHide', () => mirror.isHide);

+  }

+

+  visitLibraryDependencyMirror(LibraryDependencyMirror mirror) {

+    visit(mirror, 'isImport', () => mirror.isImport);

+    visit(mirror, 'isExport', () => mirror.isExport);

+    visit(mirror, 'sourceLibrary', () => mirror.sourceLibrary);

+    visit(mirror, 'targetLibrary', () => mirror.targetLibrary);

+    visit(mirror, 'prefix', () => mirror.prefix);

+    visit(mirror, 'combinators', () => mirror.combinators);

+    visit(mirror, 'location', () => mirror.location);

+  }

+

+  visitCommentInstanceMirror(CommentInstanceMirror mirror) {

+    visitInstanceMirror(mirror);

+    visit(mirror, 'text', () => mirror.text);

+    visit(mirror, 'trimmedText', () => mirror.trimmedText);

+    visit(mirror, 'isDocComment', () => mirror.isDocComment);

+  }

+

+  visitListInstanceMirror(ListInstanceMirror mirror) {

+    visitInstanceMirror(mirror);

+    visit(mirror, 'length', () => mirror.length);

+  }

+

+  visitMapInstanceMirror(MapInstanceMirror mirror) {

+    visitInstanceMirror(mirror);

+    visit(mirror, 'keys', () => mirror.keys);

+    visit(mirror, 'length', () => mirror.length);

+  }

+

+  visitTypeInstanceMirror(TypeInstanceMirror mirror) {

+    visitInstanceMirror(mirror);

+    visit(mirror, 'representedType', () => mirror.representedType);

+  }

+}

+

+main(List<String> arguments) {

+  asyncTest(() => analyzeUri(Uri.parse('dart:core')).

+      then((MirrorSystem mirrors) {

+    MirrorsReader reader = new SourceMirrorsReader(mirrors,

+        verbose: arguments.contains('-v'),

+        includeStackTrace: arguments.contains('-s'));

+    reader.checkMirrorSystem(mirrors);

+  }));

+}

diff --git a/tests/compiler/dart2js/mirrors/mirrors_test_helper.dart b/tests/compiler/dart2js/mirrors/mirrors_test_helper.dart
new file mode 100644
index 0000000..b6a954a
--- /dev/null
+++ b/tests/compiler/dart2js/mirrors/mirrors_test_helper.dart
@@ -0,0 +1,36 @@
+// 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.

+

+import 'dart:io';

+import 'dart:async';

+

+import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';

+import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart' as source_mirrors;

+import '../../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';

+

+TypeMirror createInstantiation(TypeSourceMirror type,

+                               List<TypeMirror> typeArguments) {

+  return type.createInstantiation(typeArguments);

+}

+

+Future<MirrorSystem> analyze(String test) {

+  Uri repository = Platform.script.resolve('../../../../');

+  Uri testUri = repository.resolve('tests/lib/mirrors/$test');

+  return analyzeUri(testUri);

+}

+

+

+Future<MirrorSystem> analyzeUri(Uri testUri) {

+  Uri repository = Platform.script.resolve('../../../../');

+  Uri libraryRoot = repository.resolve('sdk/');

+  Uri packageRoot = Uri.base.resolve('${Platform.packageRoot}/');

+  var provider = new CompilerSourceFileProvider();

+  var handler = new FormattingDiagnosticHandler(provider);

+  return source_mirrors.analyze(

+      [testUri],

+      libraryRoot,

+      packageRoot,

+      provider,

+      handler);

+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/mirrors_exports_test.dart b/tests/compiler/dart2js/mirrors_exports_test.dart
index 412014c..51da7c1 100644
--- a/tests/compiler/dart2js/mirrors_exports_test.dart
+++ b/tests/compiler/dart2js/mirrors_exports_test.dart
@@ -6,7 +6,7 @@
 import 'package:async_helper/async_helper.dart';

 import 'dart:async';

 import 'memory_compiler.dart';

-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';

+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';

 

 const SOURCE_FILES = const {

 'main.dart': '''

@@ -32,19 +32,19 @@
 

 void main() {

   asyncTest(() => mirrorSystemFor(SOURCE_FILES).then((MirrorSystem mirrors) {

-    LibraryMirror mainLibrary =

+    LibrarySourceMirror mainLibrary =

         mirrors.libraries[Uri.parse('memory:main.dart')];

     Expect.isNotNull(mainLibrary);

 

-    LibraryMirror aLibrary =

+    LibrarySourceMirror aLibrary =

         mirrors.libraries[Uri.parse('memory:a.dart')];

     Expect.isNotNull(aLibrary);

 

-    LibraryMirror bLibrary =

+    LibrarySourceMirror bLibrary =

         mirrors.libraries[Uri.parse('memory:b.dart')];

     Expect.isNotNull(bLibrary);

 

-    LibraryMirror coreLibrary =

+    LibrarySourceMirror coreLibrary =

         mirrors.libraries[Uri.parse('dart:core')];

     Expect.isNotNull(coreLibrary);

 

diff --git a/tests/compiler/dart2js/mirrors_helper.dart b/tests/compiler/dart2js/mirrors_helper.dart
index 1fb7ab3..8bba108 100644
--- a/tests/compiler/dart2js/mirrors_helper.dart
+++ b/tests/compiler/dart2js/mirrors_helper.dart
@@ -29,7 +29,7 @@
 @metadata
 /** Multiline doc comment. */
 /* Multiline comment. */ class Foo {
-
+  m(@metadata a) {}
 }
 
 
diff --git a/tests/compiler/dart2js/mirrors_lookup_test.dart b/tests/compiler/dart2js/mirrors_lookup_test.dart
index d5ebab5..4ef9b70 100644
--- a/tests/compiler/dart2js/mirrors_lookup_test.dart
+++ b/tests/compiler/dart2js/mirrors_lookup_test.dart
@@ -7,7 +7,7 @@
 import 'package:expect/expect.dart';
 import "package:async_helper/async_helper.dart";
 import 'memory_compiler.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
 
 const Map MEMORY_SOURCE_FILES = const {
@@ -40,67 +40,67 @@
 }
 
 void test(MirrorSystem mirrors) {
-  LibraryMirror dartCore = mirrors.libraries[Uri.parse('dart:core')];
+  LibrarySourceMirror dartCore = mirrors.libraries[Uri.parse('dart:core')];
   Expect.isNotNull(dartCore);
 
-  LibraryMirror dartAsync = mirrors.libraries[Uri.parse('dart:async')];
+  LibrarySourceMirror dartAsync = mirrors.libraries[Uri.parse('dart:async')];
   Expect.isNotNull(dartAsync);
 
-  LibraryMirror library = mirrors.libraries[Uri.parse('memory:main.dart')];
+  LibrarySourceMirror library = mirrors.libraries[Uri.parse('memory:main.dart')];
   Expect.isNotNull(library);
 
   // Check top-level scope.
 
-  DeclarationMirror String_ = library.lookupInScope('String');
+  DeclarationSourceMirror String_ = library.lookupInScope('String');
   Expect.isTrue(String_ is ClassMirror);
-  Expect.equals('String', String_.simpleName);
+  Expect.equals(#String, String_.simpleName);
   Expect.equals(dartCore, String_.owner);
 
   Expect.isNull(library.lookupInScope('async'));
   Expect.isNull(library.lookupInScope('Future'));
-  DeclarationMirror Future_ = library.lookupInScope('async.Future');
+  DeclarationSourceMirror Future_ = library.lookupInScope('async.Future');
   Expect.isTrue(Future_ is ClassMirror);
-  Expect.equals('Future', Future_.simpleName);
+  Expect.equals(#Future, Future_.simpleName);
   Expect.equals(dartAsync, Future_.owner);
   // Timer is not in scope.
   Expect.isNull(library.lookupInScope('Timer'));
   // async.Timer is hidden.
   Expect.isNull(library.lookupInScope('async.Timer'));
 
-  DeclarationMirror variable = library.lookupInScope('variable');
+  DeclarationSourceMirror variable = library.lookupInScope('variable');
   Expect.isTrue(variable is VariableMirror);
-  Expect.equals('variable', variable.simpleName);
-  Expect.equals('main.variable', variable.qualifiedName);
+  Expect.equals(#variable, variable.simpleName);
+  Expect.equals(#main.variable, variable.qualifiedName);
   Expect.equals(library, variable.owner);
   // Parameter `a` is not in scope.
   Expect.isNull(library.lookupInScope('a'));
   // Parameter `b` is not in scope.
   Expect.isNull(library.lookupInScope('b'));
 
-  DeclarationMirror method = library.lookupInScope('method');
+  DeclarationSourceMirror method = library.lookupInScope('method');
   Expect.isTrue(method is MethodMirror);
-  Expect.equals('method', method.simpleName);
-  Expect.equals('main.method', method.qualifiedName);
+  Expect.equals(#method, method.simpleName);
+  Expect.equals(#main.method, method.qualifiedName);
   Expect.equals(library, method.owner);
 
-  DeclarationMirror Class = library.lookupInScope('Class');
+  DeclarationSourceMirror Class = library.lookupInScope('Class');
   Expect.isTrue(Class is ClassMirror);
-  Expect.equals('Class', Class.simpleName);
-  Expect.equals('main.Class', Class.qualifiedName);
+  Expect.equals(#Class, Class.simpleName);
+  Expect.equals(#main.Class, Class.qualifiedName);
   Expect.equals(library, Class.owner);
   // Type variable `A` is not in scope.
   Expect.isNull(library.lookupInScope('A'));
 
-  DeclarationMirror Subclass = library.lookupInScope('Subclass');
+  DeclarationSourceMirror Subclass = library.lookupInScope('Subclass');
   Expect.isTrue(Subclass is ClassMirror);
-  Expect.equals('Subclass', Subclass.simpleName);
-  Expect.equals('main.Subclass', Subclass.qualifiedName);
+  Expect.equals(#Subclass, Subclass.simpleName);
+  Expect.equals(#main.Subclass, Subclass.qualifiedName);
   Expect.equals(library, Subclass.owner);
   // Type variable `B` is not in scope.
   Expect.isNull(library.lookupInScope('B'));
 
   // Check top-level declaration scope.
-  checkTopScope(DeclarationMirror declaration) {
+  checkTopScope(DeclarationSourceMirror declaration) {
     Expect.equals(String_, declaration.lookupInScope('String'));
     Expect.equals(Future_, declaration.lookupInScope('async.Future'));
     Expect.isNull(method.lookupInScope('Timer'));
@@ -127,27 +127,28 @@
 
   checkTopScope(method);
   // Parameter `a` is in scope of `method`.
+  print(method.lookupInScope('a'));
   Expect.isTrue(method.lookupInScope('a') is ParameterMirror);
   // Parameter `b` is in scope of `method`.
   Expect.isTrue(method.lookupInScope('b') is ParameterMirror);
 
   // Check class scope.
-  DeclarationMirror Class_field = Class.lookupInScope('field');
+  DeclarationSourceMirror Class_field = Class.lookupInScope('field');
   Expect.isTrue(Class_field is VariableMirror);
   Expect.notEquals(variable, Class_field);
   Expect.equals(Class, Class_field.owner);
 
-  DeclarationMirror Class_variable = Class.lookupInScope('variable');
+  DeclarationSourceMirror Class_variable = Class.lookupInScope('variable');
   Expect.isTrue(Class_variable is VariableMirror);
   Expect.notEquals(variable, Class_variable);
   Expect.equals(Class, Class_variable.owner);
 
-  DeclarationMirror Class_method = Class.lookupInScope('method');
+  DeclarationSourceMirror Class_method = Class.lookupInScope('method');
   Expect.isTrue(Class_method is MethodMirror);
   Expect.notEquals(method, Class_method);
   Expect.equals(Class, Class_method.owner);
 
-  checkClassScope(DeclarationMirror declaration, {bool parametersInScope}) {
+  checkClassScope(DeclarationSourceMirror declaration, {bool parametersInScope}) {
     Expect.equals(String_, declaration.lookupInScope('String'));
     Expect.equals(Future_, declaration.lookupInScope('async.Future'));
     Expect.isNull(declaration.lookupInScope('Timer'));
@@ -189,12 +190,12 @@
   checkClassScope(Class_method, parametersInScope: true);
 
   // Check class scope.
-  DeclarationMirror Subclass_subfield = Subclass.lookupInScope('subfield');
+  DeclarationSourceMirror Subclass_subfield = Subclass.lookupInScope('subfield');
   Expect.isTrue(Subclass_subfield is VariableMirror);
   Expect.notEquals(variable, Subclass_subfield);
   Expect.equals(Subclass, Subclass_subfield.owner);
 
-  checkSubclassScope(DeclarationMirror declaration) {
+  checkSubclassScope(DeclarationSourceMirror declaration) {
     Expect.equals(String_, declaration.lookupInScope('String'));
     Expect.equals(Future_, declaration.lookupInScope('async.Future'));
     Expect.isNull(declaration.lookupInScope('Timer'));
diff --git a/tests/compiler/dart2js/mirrors_metadata_test.dart b/tests/compiler/dart2js/mirrors_metadata_test.dart
index 66c2e41..c430997 100644
--- a/tests/compiler/dart2js/mirrors_metadata_test.dart
+++ b/tests/compiler/dart2js/mirrors_metadata_test.dart
@@ -11,12 +11,12 @@
                                 String text,
                                 String trimmedText,
                                 bool isDocComment,
-                                List<String> declarationNames) {
+                                List<Symbol> declarationNames) {
   asyncTest(() => createMirrorSystem(code).then((mirrors) {
     LibraryMirror library = mirrors.libraries[SOURCE_URI];
     Expect.isNotNull(library);
-    for (String declarationName in declarationNames) {
-      DeclarationMirror declaration = library.members[declarationName];
+    for (Symbol declarationName in declarationNames) {
+      DeclarationMirror declaration = library.declarations[declarationName];
       Expect.isNotNull(declaration);
       List<InstanceMirror> metadata = declaration.metadata;
       Expect.isNotNull(metadata);
@@ -30,7 +30,7 @@
   }));
 }
 
-void testDeclarationComment(String declaration, List<String> declarationNames) {
+void testDeclarationComment(String declaration, List<Symbol> declarationNames) {
   String text = 'Single line comment';
   String comment = '// $text';
   String code = '$comment\n$declaration';
@@ -51,18 +51,18 @@
 }
 
 void main() {
-  testDeclarationComment('var field;', ['field']);
-  testDeclarationComment('int field;', ['field']);
-  testDeclarationComment('int field = 0;', ['field']);
-  testDeclarationComment('int field1, field2;', ['field1', 'field2']);
-  testDeclarationComment('final field = 0;', ['field']);
-  testDeclarationComment('final int field = 0;', ['field']);
-  testDeclarationComment('final field1 = 0, field2 = 0;', ['field1', 'field2']);
+  testDeclarationComment('var field;', [#field]);
+  testDeclarationComment('int field;', [#field]);
+  testDeclarationComment('int field = 0;', [#field]);
+  testDeclarationComment('int field1, field2;', [#field1, #field2]);
+  testDeclarationComment('final field = 0;', [#field]);
+  testDeclarationComment('final int field = 0;', [#field]);
+  testDeclarationComment('final field1 = 0, field2 = 0;', [#field1, #field2]);
   testDeclarationComment('final int field1 = 0, field2 = 0;',
-                         ['field1', 'field2']);
-  testDeclarationComment('const field = 0;', ['field']);
-  testDeclarationComment('const int field = 0;', ['field']);
-  testDeclarationComment('const field1 = 0, field2 = 0;', ['field1', 'field2']);
+                         [#field1, #field2]);
+  testDeclarationComment('const field = 0;', [#field]);
+  testDeclarationComment('const int field = 0;', [#field]);
+  testDeclarationComment('const field1 = 0, field2 = 0;', [#field1, #field2]);
   testDeclarationComment('const int field1 = 0, field2 = 0;',
-                         ['field1', 'field2']);
+                         [#field1, #field2]);
 }
diff --git a/tests/compiler/dart2js/mirrors_mixin_test.dart b/tests/compiler/dart2js/mirrors_mixin_test.dart
index 1486851..0a94a06 100644
--- a/tests/compiler/dart2js/mirrors_mixin_test.dart
+++ b/tests/compiler/dart2js/mirrors_mixin_test.dart
@@ -35,37 +35,37 @@
       Expect.isTrue(cls is ClassMirror);

       Expect.isFalse(isMixinApplication(cls));

       Expect.isFalse(cls.isNameSynthetic);

-      Expect.isFalse(cls.isObject);

-      Expect.isTrue(cls.superclass.isObject);

+      Expect.isFalse(isObject(cls));

+      Expect.isTrue(isObject(cls.superclass));

       Expect.equals(0, cls.superinterfaces.length);

 

-      Expect.isTrue(getSuperclass(cls).isObject);

+      Expect.isTrue(isObject(getSuperclass(cls)));

       Expect.isTrue(getAppliedMixins(cls).isEmpty);

       Expect.isTrue(getExplicitInterfaces(cls).isEmpty);

     }

 

     // class A {}

-    var A = library.classes['A'];

+    var A = library.declarations[#A];

     checkSimpleClass(A);

 

     // class S {}

-    var S = library.classes['S'];

+    var S = library.declarations[#S];

     checkSimpleClass(S);

 

     // class M1 {}

-    var M1 = library.classes['M1'];

+    var M1 = library.declarations[#M1];

     checkSimpleClass(M1);

 

     // class M2 {}

-    var M2 = library.classes['M2'];

+    var M2 = library.declarations[#M2];

     checkSimpleClass(M2);

 

     // class C extends S with M1<A> {}

-    var C = library.classes['C'];

+    var C = library.declarations[#C];

     Expect.isNotNull(C);

     Expect.isTrue(C is ClassMirror);

     Expect.isFalse(isMixinApplication(C));

-    Expect.isFalse(C.isObject);

+    Expect.isFalse(isObject(C));

     Expect.equals(0, C.superinterfaces.length);

     var C_super = C.superclass;

     Expect.isNotNull(C_super);

@@ -75,7 +75,7 @@
     Expect.equals(1, C_super.superinterfaces.length);

     Expect.isTrue(containsType(M1, [A], C_super.superinterfaces));

     Expect.isTrue(isInstance(M1, [A], C_super.mixin));

-    Expect.isFalse(C_super.isObject);

+    Expect.isFalse(isObject(C_super));

     Expect.isTrue(isSameDeclaration(S, C_super.superclass));

 

     Expect.isTrue(isSameDeclaration(S, getSuperclass(C)));

@@ -83,11 +83,11 @@
     Expect.isTrue(getExplicitInterfaces(C).isEmpty);

 

     // D extends S with M1, M2 {}

-    var D = library.classes['D'];

+    var D = library.declarations[#D];

     Expect.isNotNull(D);

     Expect.isTrue(D is ClassMirror);

     Expect.isFalse(isMixinApplication(D));

-    Expect.isFalse(D.isObject);

+    Expect.isFalse(isObject(D));

     Expect.equals(0, D.superinterfaces.length);

     var D_super = D.superclass;

     Expect.isNotNull(D_super);

@@ -97,7 +97,7 @@
     Expect.equals(1, D_super.superinterfaces.length);

     Expect.isTrue(containsDeclaration(M2, D_super.superinterfaces));

     Expect.isTrue(isSameDeclaration(M2, D_super.mixin));

-    Expect.isFalse(D_super.isObject);

+    Expect.isFalse(isObject(D_super));

     Expect.isFalse(isSameDeclaration(S, D_super.superclass));

     var D_super_super = D_super.superclass;

     Expect.isNotNull(D_super_super);

@@ -107,7 +107,7 @@
     Expect.equals(1, D_super_super.superinterfaces.length);

     Expect.isTrue(containsDeclaration(M1, D_super_super.superinterfaces));

     Expect.isTrue(isSameDeclaration(M1, D_super_super.mixin));

-    Expect.isFalse(D_super_super.isObject);

+    Expect.isFalse(isObject(D_super_super));

     Expect.isTrue(isSameDeclaration(S, D_super_super.superclass));

 

     Expect.isTrue(isSameDeclaration(S, getSuperclass(D)));

@@ -115,11 +115,11 @@
     Expect.isTrue(getExplicitInterfaces(D).isEmpty);

 

     // class E extends S with M2, M1 implements A, M1 {}

-    var E = library.classes['E'];

+    var E = library.declarations[#E];

     Expect.isNotNull(E);

     Expect.isTrue(E is ClassMirror);

     Expect.isFalse(isMixinApplication(E));

-    Expect.isFalse(E.isObject);

+    Expect.isFalse(isObject(E));

     Expect.equals(2, E.superinterfaces.length);

     Expect.isTrue(containsDeclaration(A, E.superinterfaces));

     Expect.isTrue(containsDeclaration(M1, E.superinterfaces));

@@ -131,7 +131,7 @@
     Expect.equals(1, E_super.superinterfaces.length);

     Expect.isTrue(containsDeclaration(M1, E_super.superinterfaces));

     Expect.isTrue(isSameDeclaration(M1, E_super.mixin));

-    Expect.isFalse(E_super.isObject);

+    Expect.isFalse(isObject(E_super));

     Expect.isFalse(isSameDeclaration(S, E_super.superclass));

     var E_super_super = E_super.superclass;

     Expect.isNotNull(E_super_super);

@@ -141,7 +141,7 @@
     Expect.equals(1, E_super_super.superinterfaces.length);

     Expect.isTrue(containsDeclaration(M2, E_super_super.superinterfaces));

     Expect.isTrue(isSameDeclaration(M2, E_super_super.mixin));

-    Expect.isFalse(E_super_super.isObject);

+    Expect.isFalse(isObject(E_super_super));

     Expect.isTrue(isSameDeclaration(S, E_super_super.superclass));

 

     Expect.isTrue(isSameDeclaration(S, getSuperclass(E)));

@@ -149,20 +149,20 @@
     Expect.isTrue(isSameDeclarationSet([A, M1], getExplicitInterfaces(E)));

 

     // class E2 extends E {}

-    var E2 = library.classes['E2'];

+    var E2 = library.declarations[#E2];

     Expect.isTrue(isSameDeclaration(E, getSuperclass(E2)));

     Expect.isTrue(getAppliedMixins(E2).isEmpty);

     Expect.isTrue(getExplicitInterfaces(E2).isEmpty);

 

     // class F = S with M1<A>;

-    var F = library.classes['F'];

+    var F = library.declarations[#F];

     Expect.isNotNull(F);

     Expect.isTrue(F is ClassMirror);

     Expect.isFalse(F.isAbstract);

     Expect.isTrue(isMixinApplication(F));

     Expect.isFalse(F.isNameSynthetic);

-    Expect.equals('F', F.simpleName);

-    Expect.isFalse(F.isObject);

+    Expect.equals(#F, F.simpleName);

+    Expect.isFalse(isObject(F));

     Expect.equals(1, F.superinterfaces.length);

     Expect.isTrue(containsDeclaration(M1, F.superinterfaces));

     Expect.isTrue(isInstance(M1, [A], F.mixin));

@@ -170,7 +170,7 @@
     Expect.isNotNull(F_super);

     Expect.isTrue(F_super is ClassMirror);

     Expect.isFalse(isMixinApplication(F_super));

-    Expect.isFalse(F_super.isObject);

+    Expect.isFalse(isObject(F_super));

     Expect.isTrue(isSameDeclaration(S, F_super));

 

     Expect.isTrue(isSameDeclaration(S, getSuperclass(F)));

@@ -178,14 +178,14 @@
     Expect.isTrue(getExplicitInterfaces(F).isEmpty);

 

     // typedef G = abstract S with M1, M2;

-    var G = library.classes['G'];

+    var G = library.declarations[#G];

     Expect.isNotNull(G);

     Expect.isTrue(G is ClassMirror);

     Expect.isTrue(G.isAbstract);

     Expect.isTrue(isMixinApplication(G));

     Expect.isFalse(G.isNameSynthetic);

-    Expect.equals('G', G.simpleName);

-    Expect.isFalse(G.isObject);

+    Expect.equals(#G, G.simpleName);

+    Expect.isFalse(isObject(G));

     Expect.equals(1, G.superinterfaces.length);

     Expect.isTrue(containsDeclaration(M2, G.superinterfaces));

     Expect.isTrue(isSameDeclaration(M2, G.mixin));

@@ -196,7 +196,7 @@
     Expect.equals(1, G_super.superinterfaces.length);

     Expect.isTrue(containsDeclaration(M1, G_super.superinterfaces));

     Expect.isTrue(isSameDeclaration(M1, G_super.mixin));

-    Expect.isFalse(G_super.isObject);

+    Expect.isFalse(isObject(G_super));

     Expect.isTrue(isSameDeclaration(S, G_super.superclass));

 

     Expect.isTrue(isSameDeclaration(S, getSuperclass(G)));

@@ -204,14 +204,14 @@
     Expect.isTrue(getExplicitInterfaces(G).isEmpty);

 

     // typedef H = S with M2, M1 implements A, M1;

-    var H = library.classes['H'];

+    var H = library.declarations[#H];

     Expect.isNotNull(H);

     Expect.isTrue(H is ClassMirror);

     Expect.isFalse(H.isAbstract);

     Expect.isTrue(isMixinApplication(H));

     Expect.isFalse(H.isNameSynthetic);

-    Expect.equals('H', H.simpleName);

-    Expect.isFalse(H.isObject);

+    Expect.equals(#H, H.simpleName);

+    Expect.isFalse(isObject(H));

     Expect.equals(3, H.superinterfaces.length);

     Expect.isTrue(containsDeclaration(A, H.superinterfaces));

     Expect.isTrue(containsDeclaration(M1, H.superinterfaces));

@@ -224,7 +224,7 @@
     Expect.equals(1, H_super.superinterfaces.length);

     Expect.isTrue(containsDeclaration(M2, H_super.superinterfaces));

     Expect.isTrue(isSameDeclaration(M2, H_super.mixin));

-    Expect.isFalse(H_super.isObject);

+    Expect.isFalse(isObject(H_super));

     Expect.isTrue(isSameDeclaration(S, H_super.superclass));

 

     Expect.isTrue(isSameDeclaration(S, getSuperclass(H)));

@@ -232,7 +232,7 @@
     Expect.isTrue(isSameDeclarationSet([A, M1], getExplicitInterfaces(H)));

 

     // class H2 extends H {}

-    var H2 = library.classes['H2'];

+    var H2 = library.declarations[#H2];

     Expect.isTrue(isSameDeclaration(H, getSuperclass(H2)));

     Expect.isTrue(getAppliedMixins(H2).isEmpty);

     Expect.isTrue(getExplicitInterfaces(H2).isEmpty);

diff --git a/tests/compiler/dart2js/mirrors_test.dart b/tests/compiler/dart2js/mirrors_test.dart
index 3536683..13cffcc1 100644
--- a/tests/compiler/dart2js/mirrors_test.dart
+++ b/tests/compiler/dart2js/mirrors_test.dart
@@ -4,9 +4,9 @@
 
 import "package:expect/expect.dart";
 import "package:async_helper/async_helper.dart";
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart';
 import '../../../sdk/lib/_internal/compiler/implementation/filenames.dart'
        show currentDirectory;
 import '../../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
@@ -32,7 +32,7 @@
   return false;
 }
 
-DeclarationMirror findMirror(Iterable<DeclarationMirror> list, String name) {
+DeclarationMirror findMirror(Iterable<DeclarationMirror> list, Symbol name) {
   for (DeclarationMirror mirror in list) {
     if (mirror.simpleName == name) {
       return mirror;
@@ -64,13 +64,13 @@
   Expect.isNotNull(libraries, "No libraries map returned");
   Expect.isFalse(libraries.isEmpty, "Empty libraries map returned");
 
-  var helperLibrary = findMirror(libraries.values, "mirrors_helper");
+  var helperLibrary = findMirror(libraries.values, #mirrors_helper);
   Expect.isNotNull(helperLibrary, "Library 'mirrors_helper' not found");
-  Expect.stringEquals("mirrors_helper", helperLibrary.simpleName,
+  Expect.equals(#mirrors_helper, helperLibrary.simpleName,
     "Unexpected library simple name");
-  Expect.stringEquals("mirrors_helper", helperLibrary.qualifiedName,
+  Expect.equals(#mirrors_helper, helperLibrary.qualifiedName,
     "Unexpected library qualified name");
-  Expect.equals(helperLibrary, mirrors.findLibrary('mirrors_helper'));
+  Expect.equals(helperLibrary, mirrors.findLibrary(#mirrors_helper));
 
   var helperLibraryLocation = helperLibrary.location;
   Expect.isNotNull(helperLibraryLocation);
@@ -80,26 +80,18 @@
   Expect.equals(1, helperLibraryLocation.column, "Unexpected column");
 
 
-  var classes = helperLibrary.classes;
-  Expect.isNotNull(classes, "No classes map returned");
-  Expect.isFalse(classes.isEmpty, "Empty classes map returned");
+  var declarations = helperLibrary.declarations;
+  Expect.isNotNull(declarations, "No declarations map returned");
+  Expect.isFalse(declarations.isEmpty, "Empty declarations map returned");
 
-  testFoo(mirrors, helperLibrary, classes);
-  testBar(mirrors, helperLibrary, classes);
-  testBaz(mirrors, helperLibrary, classes);
+  testFoo(mirrors, helperLibrary, declarations);
+  testBar(mirrors, helperLibrary, declarations);
+  testBaz(mirrors, helperLibrary, declarations);
   // TODO(johnniwinther): Add test of class [Boz] and typedef [Func].
   // TODO(johnniwinther): Add tests of type argument substitution, which
   // is not currently implemented in dart2js.
   // TODO(johnniwinther): Add tests of Location and Source.
-  testPrivate(mirrors, helperLibrary, classes);
-  // TODO(johnniwinther): Add thorough tests of [LibraryMirror.functions],
-  // [LibraryMirror.getters], [LibraryMirror.setters], [LibraryMirror.members],
-  // and [LibraryMirror.variable].
-  Expect.isNotNull(helperLibrary.functions);
-  Expect.isNotNull(helperLibrary.members);
-  Expect.isNotNull(helperLibrary.getters);
-  Expect.isNotNull(helperLibrary.setters);
-  Expect.isNotNull(helperLibrary.variables);
+  testPrivate(mirrors, helperLibrary, declarations);
 }
 
 // Testing class Foo:
@@ -108,76 +100,68 @@
 //
 // }
 void testFoo(MirrorSystem system, LibraryMirror helperLibrary,
-             Map<String,TypeMirror> classes) {
-  var fooClass = classes["Foo"];
+             Map<Symbol, DeclarationMirror> declarations) {
+  var fooClass = declarations[#Foo];
   Expect.isNotNull(fooClass, "Type 'Foo' not found");
   Expect.isTrue(fooClass is ClassMirror,
                 "Unexpected mirror type returned");
-  Expect.stringEquals("Foo", fooClass.simpleName,
+  Expect.equals(#Foo, fooClass.simpleName,
                       "Unexpected type simple name");
-  Expect.stringEquals("mirrors_helper.Foo", fooClass.qualifiedName,
+  Expect.equals(#mirrors_helper.Foo, fooClass.qualifiedName,
                       "Unexpected type qualified name");
 
-  Expect.equals(helperLibrary, fooClass.library,
+  Expect.equals(helperLibrary, getLibrary(fooClass),
                 "Unexpected library returned from type");
 
-  Expect.isFalse(fooClass.isObject, "Class is Object");
+  Expect.isFalse(isObject(fooClass), "Class is Object");
   Expect.isFalse(fooClass.isDynamic, "Class is dynamic");
   Expect.isFalse(fooClass.isVoid, "Class is void");
-  Expect.isFalse(fooClass.isTypeVariable, "Class is a type variable");
-  Expect.isFalse(fooClass.isTypedef, "Class is a typedef");
-  Expect.isFalse(fooClass.isFunction, "Class is a function");
+  Expect.isFalse(fooClass is TypeVariableMirror, "Class is a type variable");
+  Expect.isFalse(fooClass is TypedefMirror, "Class is a typedef");
+  Expect.isFalse(fooClass is FunctionTypeMirror, "Class is a function");
 
   Expect.isTrue(fooClass.isOriginalDeclaration);
   Expect.equals(fooClass, fooClass.originalDeclaration);
 
-  Expect.isTrue(fooClass.isClass, "Class is not class");
+  Expect.isTrue(fooClass is ClassMirror, "Class is not class");
   Expect.isFalse(fooClass.isAbstract);
   Expect.isFalse(fooClass.isPrivate, "Class is private");
 
   var objectType = fooClass.superclass;
   Expect.isNotNull(objectType, "Superclass is null");
-  Expect.isTrue(objectType.isObject, "Object is not Object");
-  Expect.isFalse(objectType.isOriginalDeclaration);
+  Expect.isTrue(isObject(objectType), "Object is not Object");
+  Expect.isTrue(objectType.isOriginalDeclaration);
   Expect.isTrue(containsType(fooClass,
-                             computeSubdeclarations(objectType)),
+                             computeSubdeclarations(system, objectType)),
                 "Class is not subclass of superclass");
 
   var fooInterfaces = fooClass.superinterfaces;
   Expect.isNotNull(fooInterfaces, "Interfaces map is null");
   Expect.isTrue(fooInterfaces.isEmpty, "Interfaces map is not empty");
 
-  var fooSubdeclarations = computeSubdeclarations(fooClass);
+  var fooSubdeclarations = computeSubdeclarations(system, fooClass);
   Expect.equals(1, count(fooSubdeclarations), "Unexpected subtype count");
   for (var fooSubdeclaration in fooSubdeclarations) {
     Expect.equals(fooClass, fooSubdeclaration.superclass.originalDeclaration);
   }
 
-  Expect.throws(() => fooClass.typeArguments,
-                (exception) => true,
-                "Class has type arguments");
+  Expect.isTrue(fooClass.typeArguments.isEmpty);
   var fooClassTypeVariables = fooClass.typeVariables;
   Expect.isNotNull(fooClassTypeVariables, "Type variable list is null");
   Expect.isTrue(fooClassTypeVariables.isEmpty,
                 "Type variable list is not empty");
 
-  var fooClassMembers = fooClass.members;
+  var fooClassMembers = fooClass.declarations;
   Expect.isNotNull(fooClassMembers, "Declared members map is null");
-  Expect.isTrue(fooClassMembers.isEmpty, "Declared members map is unempty");
+  Expect.equals(1, fooClassMembers.length);
 
-  var fooClassConstructors = fooClass.constructors;
-  Expect.isNotNull(fooClassConstructors, "Constructors map is null");
-  Expect.isTrue(fooClassConstructors.isEmpty,
-                "Constructors map is unempty");
-
-  // TODO(johnniwinther): Add thorough tests of [ClassMirror.functions],
-  // [ClassMirror.getters], [ClassMirror.setters], [ClassMirror.members],
-  // and [ClassMirror.variable].
-  Expect.isNotNull(fooClass.functions);
-  Expect.isNotNull(fooClass.members);
-  Expect.isNotNull(fooClass.getters);
-  Expect.isNotNull(fooClass.setters);
-  Expect.isNotNull(fooClass.variables);
+  var fooM = fooClassMembers[#m];
+  Expect.isNotNull(fooM);
+  Expect.isTrue(fooM is MethodMirror);
+  Expect.equals(1, fooM.parameters.length);
+  var fooMa = fooM.parameters[0];
+  Expect.isNotNull(fooMa);
+  Expect.isTrue(fooMa is ParameterMirror);
 
   //////////////////////////////////////////////////////////////////////////////
   // Metadata tests
@@ -191,7 +175,7 @@
 
   var dartMirrorsLibrary = system.libraries[DART_MIRRORS_URI];
   Expect.isNotNull(dartMirrorsLibrary);
-  var commentType = dartMirrorsLibrary.classes['Comment'];
+  var commentType = dartMirrorsLibrary.declarations[#Comment];
   Expect.isNotNull(commentType);
 
   // /// Singleline doc comment.
@@ -215,7 +199,7 @@
   Expect.isTrue(metadata is TypeInstanceMirror);
   var metadataType = metadata.representedType;
   Expect.isNotNull(metadataType);
-  Expect.stringEquals('Metadata', metadataType.simpleName);
+  Expect.equals(#Metadata, metadataType.simpleName);
 
   // // This is intentionally the type literal.
   metadata = metadataList[metadataListIndex++];
@@ -262,7 +246,7 @@
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  InstanceMirror data = metadata.getField('data');
+  InstanceMirror data = metadata.getField(#data);
   Expect.isNotNull(data);
   Expect.isTrue(data.hasReflectee);
   Expect.isNull(data.reflectee);
@@ -273,7 +257,7 @@
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  data = metadata.getField('data');
+  data = metadata.getField(#data);
   Expect.isNotNull(data);
   Expect.isTrue(data.hasReflectee);
   Expect.isTrue(data.reflectee);
@@ -284,7 +268,7 @@
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  data = metadata.getField('data');
+  data = metadata.getField(#data);
   Expect.isNotNull(data);
   Expect.isTrue(data.hasReflectee);
   Expect.isFalse(data.reflectee);
@@ -295,7 +279,7 @@
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  data = metadata.getField('data');
+  data = metadata.getField(#data);
   Expect.isNotNull(data);
   Expect.isTrue(data.hasReflectee);
   Expect.equals(0, data.reflectee);
@@ -306,7 +290,7 @@
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  data = metadata.getField('data');
+  data = metadata.getField(#data);
   Expect.isNotNull(data);
   Expect.isTrue(data.hasReflectee);
   Expect.equals(1.5, data.reflectee);
@@ -317,7 +301,7 @@
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  data = metadata.getField('data');
+  data = metadata.getField(#data);
   Expect.isNotNull(data);
   Expect.isTrue(data.hasReflectee);
   Expect.stringEquals("Foo", data.reflectee);
@@ -328,13 +312,13 @@
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  data = metadata.getField('data');
+  data = metadata.getField(#data);
   Expect.isTrue(data is ListInstanceMirror);
   Expect.isFalse(data.hasReflectee);
   Expect.throws(() => data.reflectee, (_) => true);
   ListInstanceMirror listData = data;
   Expect.equals(1, listData.length);
-  InstanceMirror element = listData[0];
+  InstanceMirror element = listData.getElement(0);
   Expect.isNotNull(element);
   Expect.isTrue(element.hasReflectee);
   Expect.stringEquals("Foo", element.reflectee);
@@ -345,7 +329,7 @@
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  data = metadata.getField('data');
+  data = metadata.getField(#data);
   Expect.isTrue(data is MapInstanceMirror);
   Expect.isFalse(data.hasReflectee);
   Expect.throws(() => data.reflectee, (_) => true);
@@ -354,19 +338,19 @@
   var it = mapData.keys.iterator;
   Expect.isTrue(it.moveNext());
   Expect.stringEquals('foo', it.current);
-  element = mapData['foo'];
+  element = mapData.getValue('foo');
   Expect.isNotNull(element);
   Expect.isTrue(element.hasReflectee);
   Expect.stringEquals("Foo", element.reflectee);
-  Expect.isNull(mapData['bar']);
+  Expect.isNull(mapData.getValue('bar'));
 
   // @metadata
-  metadata = metadataList[metadataListIndex++];
+  var metadataRef = metadata = metadataList[metadataListIndex++];
   Expect.isTrue(metadata is InstanceMirror);
   Expect.isFalse(metadata.hasReflectee);
   Expect.throws(() => metadata.reflectee, (_) => true);
   Expect.equals(metadataType.originalDeclaration, metadata.type);
-  data = metadata.getField('data');
+  data = metadata.getField(#data);
   Expect.isNotNull(data);
   Expect.isTrue(data.hasReflectee);
   Expect.isNull(data.reflectee);
@@ -399,6 +383,10 @@
 
   Expect.equals(metadataList.length, metadataListIndex);
 
+  Expect.isNotNull(fooMa.metadata);
+  Expect.equals(1, fooMa.metadata.length);
+  Expect.equals(metadataRef, fooMa.metadata[0]);
+
   //////////////////////////////////////////////////////////////////////////////
   // Location test
   //////////////////////////////////////////////////////////////////////////////
@@ -409,7 +397,7 @@
   // leading comment.
   Expect.equals(376, fooClassLocation.offset, "Unexpected offset");
   // Expect the location to end with the class body.
-  Expect.equals(332, fooClassLocation.length, "Unexpected length");
+  Expect.equals(351, fooClassLocation.length, "Unexpected length");
   Expect.equals(18, fooClassLocation.line, "Unexpected line");
   Expect.equals(1, fooClassLocation.column, "Unexpected column");
 
@@ -421,46 +409,46 @@
 //
 // }
 void testBar(MirrorSystem system, LibraryMirror helperLibrary,
-             Map<String,TypeMirror> classes) {
-  var barClass = classes["Bar"];
+             Map<Symbol, DeclarationMirror> classes) {
+  var barClass = classes[#Bar];
   Expect.isNotNull(barClass, "Type 'Bar' not found");
   Expect.isTrue(barClass is ClassMirror,
                "Unexpected mirror type returned");
-  Expect.stringEquals("Bar", barClass.simpleName,
+  Expect.equals(#Bar, barClass.simpleName,
                       "Unexpected type simple name");
-  Expect.stringEquals("mirrors_helper.Bar", barClass.qualifiedName,
-                      "Unexpected type qualified name");
+  Expect.equals(#mirrors_helper.Bar, barClass.qualifiedName,
+                "Unexpected type qualified name");
 
-  Expect.equals(helperLibrary, barClass.library,
+  Expect.equals(helperLibrary, getLibrary(barClass),
                 "Unexpected library returned from type");
 
-  Expect.isFalse(barClass.isObject, "Interface is Object");
+  Expect.isFalse(isObject(barClass), "Interface is Object");
   Expect.isFalse(barClass.isDynamic, "Interface is dynamic");
   Expect.isFalse(barClass.isVoid, "Interface is void");
-  Expect.isFalse(barClass.isTypeVariable, "Interface is a type variable");
-  Expect.isFalse(barClass.isTypedef, "Interface is a typedef");
-  Expect.isFalse(barClass.isFunction, "Interface is a function");
+  Expect.isFalse(barClass is TypeVariableMirror, "Interface is a type variable");
+  Expect.isFalse(barClass is TypedefMirror, "Interface is a typedef");
+  Expect.isFalse(barClass is FunctionTypeMirror, "Interface is a function");
 
   Expect.isTrue(barClass.isOriginalDeclaration);
   Expect.equals(barClass, barClass.originalDeclaration);
 
-  Expect.isTrue(barClass.isClass);
+  Expect.isTrue(barClass is ClassMirror);
   Expect.isTrue(barClass.isAbstract);
   Expect.isFalse(barClass.isPrivate, "Interface is private");
 
   var objectType = barClass.superclass;
   Expect.isNotNull(objectType, "Superclass is null");
-  Expect.isTrue(objectType.isObject, "Object is not Object");
-  Expect.isFalse(objectType.isOriginalDeclaration);
+  Expect.isTrue(isObject(objectType), "Object is not Object");
+  Expect.isTrue(objectType.isOriginalDeclaration);
   Expect.isTrue(containsType(barClass,
-                             computeSubdeclarations(objectType)),
+                             computeSubdeclarations(system, objectType)),
                 "Class is not subclass of superclass");
 
   var barInterfaces = barClass.superinterfaces;
   Expect.isNotNull(barInterfaces, "Interfaces map is null");
   Expect.isTrue(barInterfaces.isEmpty, "Interfaces map is not empty");
 
-  var barSubdeclarations = computeSubdeclarations(barClass);
+  var barSubdeclarations = computeSubdeclarations(system, barClass);
   Expect.equals(1, count(barSubdeclarations), "Unexpected subtype count");
   for (var barSubdeclaration in barSubdeclarations) {
     Expect.isTrue(containsType(barClass,
@@ -468,9 +456,7 @@
                   "Interface is not superinterface of subclass");
   }
 
-  Expect.throws(() => barClass.typeArguments,
-              (exception) => true,
-              "Interface has type arguments");
+  Expect.isTrue(barClass.typeArguments.isEmpty);
   var barInterfaceTypeVariables = barClass.typeVariables;
   Expect.isNotNull(barInterfaceTypeVariables, "Type variable list is null");
   Expect.isFalse(barInterfaceTypeVariables.isEmpty,
@@ -480,17 +466,12 @@
 
   var barE = barInterfaceTypeVariables[0];
   Expect.isNotNull(barE, "Type variable is null");
-  Expect.isTrue(barE.isTypeVariable, "Type variable is not type variable");
+  Expect.isTrue(barE is TypeVariableMirror);
 
-  var barInterfaceMembers = barClass.members;
+  var barInterfaceMembers = barClass.declarations;
   Expect.isNotNull(barInterfaceMembers, "Declared members map is null");
   Expect.isTrue(barInterfaceMembers.isEmpty,
-                "Declared members map is unempty");
-
-  var barInterfaceConstructors = barClass.constructors;
-  Expect.isNotNull(barInterfaceConstructors, "Constructors map is null");
-  Expect.isTrue(barInterfaceConstructors.isEmpty,
-                "Constructors map is unempty");
+                "Declarations map is unempty");
 
   var metadata = barClass.metadata;
   Expect.isNotNull(metadata);
@@ -512,39 +493,39 @@
 //   int operator -() => 0;
 // }
 void testBaz(MirrorSystem system, LibraryMirror helperLibrary,
-             Map<String,TypeMirror> classes) {
-  var bazClass = classes["Baz"];
+             Map<Symbol, DeclarationMirror> declarations) {
+  var bazClass = declarations[#Baz];
   Expect.isNotNull(bazClass, "Type 'Baz' not found");
   Expect.isTrue(bazClass is ClassMirror,
                 "Unexpected mirror type returned");
-  Expect.stringEquals("Baz", bazClass.simpleName,
-                      "Unexpected type simple name");
-  Expect.stringEquals("mirrors_helper.Baz", bazClass.qualifiedName,
-                      "Unexpected type qualified name");
+  Expect.equals(#Baz, bazClass.simpleName,
+                "Unexpected type simple name");
+  Expect.equals(#mirrors_helper.Baz, bazClass.qualifiedName,
+                "Unexpected type qualified name");
 
-  Expect.equals(helperLibrary, bazClass.library,
+  Expect.equals(helperLibrary, getLibrary(bazClass),
                 "Unexpected library returned from type");
 
-  Expect.isFalse(bazClass.isObject, "Class is Object");
+  Expect.isFalse(isObject(bazClass), "Class is Object");
   Expect.isFalse(bazClass.isDynamic, "Class is dynamic");
   Expect.isFalse(bazClass.isVoid, "Class is void");
-  Expect.isFalse(bazClass.isTypeVariable, "Class is a type variable");
-  Expect.isFalse(bazClass.isTypedef, "Class is a typedef");
-  Expect.isFalse(bazClass.isFunction, "Class is a function");
+  Expect.isFalse(bazClass is TypeVariableMirror, "Class is a type variable");
+  Expect.isFalse(bazClass is TypedefMirror, "Class is a typedef");
+  Expect.isFalse(bazClass is FunctionTypeMirror, "Class is a function");
 
   Expect.isTrue(bazClass.isOriginalDeclaration);
   Expect.equals(bazClass, bazClass.originalDeclaration);
 
-  Expect.isTrue(bazClass.isClass, "Class is not class");
+  Expect.isTrue(bazClass is ClassMirror, "Class is not class");
   Expect.isFalse(bazClass.isAbstract);
   Expect.isFalse(bazClass.isPrivate, "Class is private");
 
   var objectType = bazClass.superclass;
   Expect.isNotNull(objectType, "Superclass is null");
-  Expect.isTrue(objectType.isObject, "Object is not Object");
-  Expect.isFalse(objectType.isOriginalDeclaration);
+  Expect.isTrue(isObject(objectType), "Object is not Object");
+  Expect.isTrue(objectType.isOriginalDeclaration);
   Expect.isTrue(containsType(bazClass,
-                             computeSubdeclarations(objectType)),
+                             computeSubdeclarations(system, objectType)),
                 "Class is not subclass of superclass");
 
   var bazInterfaces = bazClass.superinterfaces;
@@ -552,14 +533,14 @@
   Expect.isTrue(!bazInterfaces.isEmpty, "Interfaces map is empty");
   for (var bazInterface in bazInterfaces) {
     Expect.isTrue(containsType(bazClass,
-                               computeSubdeclarations(objectType)),
+                               computeSubdeclarations(system, objectType)),
                   "Class is not subclass of superinterface");
   }
 
-  var bazSubdeclarations = computeSubdeclarations(bazClass);
+  var bazSubdeclarations = computeSubdeclarations(system, bazClass);
   Expect.equals(0, count(bazSubdeclarations), "Unexpected subtype count");
 
-  var barInterface = findMirror(bazInterfaces, "Bar");
+  var barInterface = findMirror(bazInterfaces, #Bar);
   Expect.isNotNull(barInterface, "Interface bar is missing");
   Expect.isFalse(barInterface.isOriginalDeclaration);
   var barInterfaceTypeArguments = barInterface.typeArguments;
@@ -567,9 +548,7 @@
   Expect.equals(1, barInterfaceTypeArguments.length,
                 "Type arguments is empty");
 
-  Expect.throws(() => bazClass.typeArguments,
-                (exception) => true,
-                "Class has type arguments");
+  Expect.isTrue(bazClass.typeArguments.isEmpty, "Class has type arguments");
   var bazClassTypeVariables = bazClass.typeVariables;
   Expect.isNotNull(bazClassTypeVariables, "Type variable list is null");
   Expect.equals(2, bazClassTypeVariables.length,
@@ -577,29 +556,29 @@
 
   var bazE = bazClassTypeVariables[0];
   Expect.isNotNull(bazE, "Type variable is null");
-  Expect.stringEquals('E', bazE.simpleName, "Unexpected simpleName");
-  Expect.stringEquals('mirrors_helper.Baz.E', bazE.qualifiedName,
-                      "Unexpected qualifiedName");
-  Expect.equals(bazClass, bazE.declarer,
+  Expect.equals(#E, bazE.simpleName, "Unexpected simpleName");
+  Expect.equals(#mirrors_helper.Baz.E, bazE.qualifiedName,
+                "Unexpected qualifiedName");
+  Expect.equals(bazClass, bazE.owner,
                 "Unexpected type variable declarer");
   var bazEbound = bazE.upperBound;
   Expect.isNotNull(bazEbound);
-  Expect.isFalse(bazEbound.isOriginalDeclaration);
-  Expect.isTrue(bazEbound.isObject, "Bound is not object");
+  Expect.isTrue(bazEbound.isOriginalDeclaration);
+  Expect.isTrue(isObject(bazEbound), "Bound is not object");
 
   var bazF = bazClassTypeVariables[1];
   Expect.isNotNull(bazF, "Type variable is null");
-  Expect.stringEquals('F', bazF.simpleName, "Unexpected simpleName");
-  Expect.stringEquals('mirrors_helper.Baz.F', bazF.qualifiedName,
-                      "Unexpected qualifiedName");
-  Expect.equals(bazClass, bazF.declarer);
+  Expect.equals(#F, bazF.simpleName, "Unexpected simpleName");
+  Expect.equals(#mirrors_helper.Baz.F, bazF.qualifiedName,
+                "Unexpected qualifiedName");
+  Expect.equals(bazClass, bazF.owner);
   var bazFbound = bazF.upperBound;
   Expect.isNotNull(bazFbound);
-  Expect.isFalse(bazFbound.isOriginalDeclaration);
-  Expect.stringEquals("mirrors_helper.Foo", bazFbound.qualifiedName,
-                      "Bound is not Foo");
+  Expect.isTrue(bazFbound.isOriginalDeclaration);
+  Expect.equals(#mirrors_helper.Foo, bazFbound.qualifiedName,
+                "Bound is not Foo");
 
-  var bazClassMembers = bazClass.members;
+  var bazClassMembers = bazClass.declarations;
   Expect.isNotNull(bazClassMembers, "Declared members map is null");
   Expect.equals(8, bazClassMembers.length,
                 "Unexpected number of declared members");
@@ -607,20 +586,16 @@
   ////////////////////////////////////////////////////////////////////////////
   // static method1(e) {}
   ////////////////////////////////////////////////////////////////////////////
-  var method1 = bazClassMembers["method1"];
+  var method1 = bazClassMembers[#method1];
   Expect.isNotNull(method1, "method1 not found");
-  Expect.stringEquals('method1', method1.simpleName,
-                      "Unexpected method simpleName");
-  Expect.stringEquals('mirrors_helper.Baz.method1', method1.qualifiedName,
-                      "Unexpected method qualifiedName");
+  Expect.equals(#method1, method1.simpleName);
+  Expect.equals(#mirrors_helper.Baz.method1, method1.qualifiedName);
   Expect.equals(method1.owner, bazClass);
   Expect.isFalse(method1.isTopLevel);
+  Expect.isTrue(method1 is MethodMirror);
   Expect.isFalse(method1.isConstructor);
-  Expect.isFalse(method1.isVariable);
-  Expect.isTrue(method1.isMethod);
   Expect.isFalse(method1.isPrivate);
   Expect.isTrue(method1.isStatic);
-  Expect.isTrue(method1 is MethodMirror);
   Expect.isTrue(method1.isRegularMethod);
   Expect.isFalse(method1.isConstConstructor);
   Expect.isFalse(method1.isGenerativeConstructor);
@@ -632,12 +607,12 @@
 
   var dynamicType = method1.returnType;
   Expect.isNotNull(dynamicType, "Return type was null");
-  Expect.isFalse(dynamicType.isObject, "dynamic is Object");
+  Expect.isFalse(isObject(dynamicType), "dynamic is Object");
   Expect.isTrue(dynamicType.isDynamic, "dynamic is not dynamic");
   Expect.isFalse(dynamicType.isVoid, "dynamic is void");
-  Expect.isFalse(dynamicType.isTypeVariable, "dynamic is a type variable");
-  Expect.isFalse(dynamicType.isTypedef, "dynamic is a typedef");
-  Expect.isFalse(dynamicType.isFunction, "dynamic is a function");
+  Expect.isFalse(dynamicType is TypeVariableMirror, "dynamic is a type variable");
+  Expect.isFalse(dynamicType is TypedefMirror, "dynamic is a typedef");
+  Expect.isFalse(dynamicType is FunctionTypeMirror, "dynamic is a function");
 
   var method1Parameters = method1.parameters;
   Expect.isNotNull(method1Parameters, "Method parameters is null");
@@ -645,11 +620,8 @@
   var method1Parameter1 = method1Parameters[0];
   Expect.isNotNull(method1Parameter1, "Parameter is null");
   Expect.equals(dynamicType, method1Parameter1.type);
-  Expect.stringEquals("e", method1Parameter1.simpleName,
-                      "Unexpected parameter simpleName");
-  Expect.stringEquals("mirrors_helper.Baz.method1#e",
-                      method1Parameter1.qualifiedName,
-                      "Unexpected parameter qualifiedName");
+  Expect.equals(#e, method1Parameter1.simpleName);
+  Expect.equals(#mirrors_helper.Baz.method1.e, method1Parameter1.qualifiedName);
   Expect.isFalse(method1Parameter1.hasDefaultValue,
     "Parameter has default value");
   Expect.isNull(method1Parameter1.defaultValue,
@@ -659,20 +631,16 @@
   ////////////////////////////////////////////////////////////////////////////
   // static void method2(E e, [F f = null]) {}
   ////////////////////////////////////////////////////////////////////////////
-  var method2 = bazClassMembers["method2"];
+  var method2 = bazClassMembers[#method2];
   Expect.isNotNull(method2, "method2 not found");
-  Expect.stringEquals('method2', method2.simpleName,
-                      "Unexpected method simpleName");
-  Expect.stringEquals('mirrors_helper.Baz.method2', method2.qualifiedName,
-                      "Unexpected method qualifiedName");
+  Expect.equals(#method2, method2.simpleName);
+  Expect.equals(#mirrors_helper.Baz.method2, method2.qualifiedName);
   Expect.equals(method2.owner, bazClass);
   Expect.isFalse(method2.isTopLevel);
+  Expect.isTrue(method2 is MethodMirror);
   Expect.isFalse(method2.isConstructor);
-  Expect.isFalse(method2.isVariable);
-  Expect.isTrue(method2.isMethod);
   Expect.isFalse(method2.isPrivate);
   Expect.isFalse(method2.isStatic);
-  Expect.isTrue(method2 is MethodMirror);
   Expect.isTrue(method2.isRegularMethod);
   Expect.isFalse(method2.isConstConstructor);
   Expect.isFalse(method2.isGenerativeConstructor);
@@ -684,12 +652,12 @@
 
   var voidType = method2.returnType;
   Expect.isNotNull(voidType, "Return type was null");
-  Expect.isFalse(voidType.isObject, "void is Object");
+  Expect.isFalse(isObject(voidType), "void is Object");
   Expect.isFalse(voidType.isDynamic, "void is dynamic");
   Expect.isTrue(voidType.isVoid, "void is not void");
-  Expect.isFalse(voidType.isTypeVariable, "void is a type variable");
-  Expect.isFalse(voidType.isTypedef, "void is a typedef");
-  Expect.isFalse(voidType.isFunction, "void is a function");
+  Expect.isFalse(voidType is TypeVariableMirror, "void is a type variable");
+  Expect.isFalse(voidType is TypedefMirror, "void is a typedef");
+  Expect.isFalse(voidType is FunctionTypeMirror, "void is a function");
 
   var method2Parameters = method2.parameters;
   Expect.isNotNull(method2Parameters, "Method parameters is null");
@@ -697,11 +665,8 @@
   var method2Parameter1 = method2Parameters[0];
   Expect.isNotNull(method2Parameter1, "Parameter is null");
   Expect.equals(bazE, method2Parameter1.type);
-  Expect.stringEquals("e", method2Parameter1.simpleName,
-                      "Unexpected parameter simpleName");
-  Expect.stringEquals("mirrors_helper.Baz.method2#e",
-                      method2Parameter1.qualifiedName,
-                      "Unexpected parameter qualifiedName");
+  Expect.equals(#e, method2Parameter1.simpleName);
+  Expect.equals(#mirrors_helper.Baz.method2.e, method2Parameter1.qualifiedName);
   Expect.isFalse(method2Parameter1.hasDefaultValue,
                       "Parameter has default value");
   Expect.isNull(method2Parameter1.defaultValue,
@@ -710,34 +675,28 @@
   var method2Parameter2 = method2Parameters[1];
   Expect.isNotNull(method2Parameter2, "Parameter is null");
   Expect.equals(bazF, method2Parameter2.type);
-  Expect.stringEquals("f", method2Parameter2.simpleName,
-                      "Unexpected parameter simpleName");
-  Expect.stringEquals("mirrors_helper.Baz.method2#f",
-                      method2Parameter2.qualifiedName,
-                      "Unexpected parameter qualifiedName");
+  Expect.equals(#f, method2Parameter2.simpleName);
+  Expect.equals(#mirrors_helper.Baz.method2.f,
+                method2Parameter2.qualifiedName);
   Expect.isTrue(method2Parameter2.hasDefaultValue,
                  "Parameter has default value");
-  Expect.stringEquals("null", method2Parameter2.defaultValue,
-                      "Parameter default value is non-null");
+  Expect.isNotNull(method2Parameter2.defaultValue,
+                   "Parameter default value is null");
   Expect.isTrue(method2Parameter2.isOptional, "Parameter is not optional");
 
   ////////////////////////////////////////////////////////////////////////////
   // Baz<E,F> method3(E func1(F f), Func<E,F> func2) => null;
   ////////////////////////////////////////////////////////////////////////////
-  var method3 = bazClassMembers["method3"];
+  var method3 = bazClassMembers[#method3];
   Expect.isNotNull(method3, "method3 not found");
-  Expect.stringEquals('method3', method3.simpleName,
-                      "Unexpected method simpleName");
-  Expect.stringEquals('mirrors_helper.Baz.method3', method3.qualifiedName,
-                      "Unexpected method qualifiedName");
+  Expect.equals(#method3, method3.simpleName);
+  Expect.equals(#mirrors_helper.Baz.method3, method3.qualifiedName);
   Expect.equals(method3.owner, bazClass);
   Expect.isFalse(method3.isTopLevel);
+  Expect.isTrue(method3 is MethodMirror);
   Expect.isFalse(method3.isConstructor);
-  Expect.isFalse(method3.isVariable);
-  Expect.isTrue(method3.isMethod);
   Expect.isFalse(method3.isPrivate);
   Expect.isFalse(method3.isStatic);
-  Expect.isTrue(method3 is MethodMirror);
   Expect.isTrue(method3.isRegularMethod);
   Expect.isFalse(method3.isConstConstructor);
   Expect.isFalse(method3.isGenerativeConstructor);
@@ -773,15 +732,12 @@
                 "Return type of 'func1' is not a E");
   Expect.isNotNull(method3Parameter1type.parameters[0],
                 "Parameter 1 of 'func1' is null");
-  Expect.stringEquals('f', method3Parameter1type.parameters[0].simpleName,
-                "Unexpected name parameter 1 of 'func1'");
+  Expect.equals(#f, method3Parameter1type.parameters[0].simpleName);
   Expect.equals(bazF, method3Parameter1type.parameters[0].type,
                 "Argument type of 'func1' is not a F");
-  Expect.stringEquals("func1", method3Parameter1.simpleName,
-                      "Unexpected parameter simpleName");
-  Expect.stringEquals("mirrors_helper.Baz.method3#func1",
-                      method3Parameter1.qualifiedName,
-                      "Unexpected parameter qualifiedName");
+  Expect.equals(#func1, method3Parameter1.simpleName);
+  Expect.equals(#mirrors_helper.Baz.method3.func1,
+                method3Parameter1.qualifiedName);
   Expect.isFalse(method3Parameter1.hasDefaultValue,
                  "Parameter has default value");
   Expect.isNull(method3Parameter1.defaultValue,
@@ -792,48 +748,33 @@
   Expect.isNotNull(method3Parameter2, "Parameter is null");
   var funcTypedef = method3Parameter2.type;
   Expect.isNotNull(funcTypedef, "Parameter type is null");
-  Expect.stringEquals("Func", funcTypedef.simpleName,
-                      "Unexpected simpleName");
-  Expect.stringEquals("mirrors_helper.Func", funcTypedef.qualifiedName,
-                      "Unexpected simpleName");
-  Expect.isFalse(funcTypedef.isObject, "Typedef is Object");
+  Expect.equals(#Func, funcTypedef.simpleName);
+  Expect.equals(#mirrors_helper.Func, funcTypedef.qualifiedName);
+  Expect.isFalse(isObject(funcTypedef), "Typedef is Object");
   Expect.isFalse(funcTypedef.isDynamic, "Typedef is dynamic");
   Expect.isFalse(funcTypedef.isVoid, "Typedef is void");
-  Expect.isFalse(funcTypedef.isTypeVariable, "Typedef is a type variable");
-  Expect.isTrue(funcTypedef.isTypedef, "Typedef is not a typedef");
-  Expect.isFalse(funcTypedef.isFunction, "Typedef is a function");
+  Expect.isFalse(funcTypedef is TypeVariableMirror, "Typedef is a type variable");
+  Expect.isTrue(funcTypedef is TypedefMirror, "Typedef is not a typedef");
+  Expect.isFalse(funcTypedef is FunctionTypeMirror, "Typedef is a function");
 
-  Expect.equals(helperLibrary, funcTypedef.library,
+  Expect.equals(helperLibrary, getLibrary(funcTypedef),
                 "Unexpected typedef library");
-  Expect.isNull(funcTypedef.superclass, "Non-null superclass on typedef");
-  Expect.isNotNull(funcTypedef.superinterfaces);
-  Expect.isTrue(funcTypedef.superinterfaces.isEmpty);
-  Expect.isNotNull(funcTypedef.members);
-  Expect.isTrue(funcTypedef.members.isEmpty);
 
-  // TODO(johnniwinther): Returned typedef should not be the original
-  // declaration:
-  Expect.isTrue(funcTypedef.isOriginalDeclaration);
-  Expect.isFalse(funcTypedef.isClass, "Typedef is class");
+  Expect.isFalse(funcTypedef.isOriginalDeclaration);
+  Expect.isFalse(funcTypedef is ClassMirror, "Typedef is class");
   Expect.isFalse(funcTypedef.isPrivate, "Typedef is private");
-  // TODO(johnniwinther): Should not throw an exception since the type should
-  // not be the original declaration.
-  Expect.throws(() => funcTypedef.typeArguments,
-                (exception) => true,
-                "Typedef has type arguments");
+  Expect.equals(2, funcTypedef.typeArguments.length);
   var funcTypedefTypeVariables = funcTypedef.typeVariables;
   Expect.isNotNull(funcTypedefTypeVariables);
   Expect.equals(2, funcTypedefTypeVariables.length);
 
-  var funcTypedefDefinition = funcTypedef.value;
+  var funcTypedefDefinition = funcTypedef.referent;
   Expect.isNotNull(funcTypedefDefinition);
   Expect.isTrue(funcTypedefDefinition is FunctionTypeMirror);
 
-  Expect.stringEquals("func2", method3Parameter2.simpleName,
-                      "Unexpected parameter simpleName");
-  Expect.stringEquals("mirrors_helper.Baz.method3#func2",
-                      method3Parameter2.qualifiedName,
-                      "Unexpected parameter qualifiedName");
+  Expect.equals(#func2, method3Parameter2.simpleName);
+  Expect.equals(#mirrors_helper.Baz.method3.func2,
+                method3Parameter2.qualifiedName);
   Expect.isFalse(method3Parameter2.hasDefaultValue,
                  "Parameter 'func2' has default value: "
                  "${method3Parameter2.defaultValue}");
@@ -844,22 +785,20 @@
   ////////////////////////////////////////////////////////////////////////////
   // bool operator==(Object other) => false;
   ////////////////////////////////////////////////////////////////////////////
-  var operator_eq = bazClassMembers['=='];
+  var operator_eq = bazClassMembers[const Symbol('==')];
   Expect.isNotNull(operator_eq, "operator == not found");
-  Expect.stringEquals('==', operator_eq.simpleName,
-                      "Unexpected method simpleName");
+  Expect.equals(const Symbol('=='), operator_eq.simpleName,
+                "Unexpected method simpleName");
   Expect.stringEquals('operator ==', displayName(operator_eq));
-  Expect.stringEquals('mirrors_helper.Baz.==',
-                      operator_eq.qualifiedName,
-                      "Unexpected method qualifiedName");
+  Expect.equals(const Symbol('mirrors_helper.Baz.=='),
+                operator_eq.qualifiedName,
+                "Unexpected method qualifiedName");
   Expect.equals(operator_eq.owner, bazClass);
   Expect.isFalse(operator_eq.isTopLevel);
+  Expect.isTrue(operator_eq is MethodMirror);
   Expect.isFalse(operator_eq.isConstructor);
-  Expect.isFalse(operator_eq.isVariable);
-  Expect.isTrue(operator_eq.isMethod);
   Expect.isFalse(operator_eq.isPrivate);
   Expect.isFalse(operator_eq.isStatic);
-  Expect.isTrue(operator_eq is MethodMirror);
   Expect.isTrue(operator_eq.isRegularMethod);
   Expect.isFalse(operator_eq.isConstConstructor);
   Expect.isFalse(operator_eq.isGenerativeConstructor);
@@ -873,22 +812,20 @@
   ////////////////////////////////////////////////////////////////////////////
   // int operator -() => 0;
   ////////////////////////////////////////////////////////////////////////////
-  var operator_negate = bazClassMembers[Mirror.UNARY_MINUS];
+  var operator_negate = bazClassMembers[const Symbol('unary-')];
   Expect.isNotNull(operator_negate, "operator < not found");
-  Expect.stringEquals(Mirror.UNARY_MINUS, operator_negate.simpleName,
+  Expect.equals(const Symbol('unary-'), operator_negate.simpleName,
                       "Unexpected method simpleName");
   Expect.stringEquals('operator -', displayName(operator_negate));
-  Expect.stringEquals('mirrors_helper.Baz.${Mirror.UNARY_MINUS}',
+  Expect.equals(const Symbol('mirrors_helper.Baz.unary-'),
                       operator_negate.qualifiedName,
                       "Unexpected method qualifiedName");
   Expect.equals(operator_negate.owner, bazClass);
   Expect.isFalse(operator_negate.isTopLevel);
+  Expect.isTrue(operator_negate is MethodMirror);
   Expect.isFalse(operator_negate.isConstructor);
-  Expect.isFalse(operator_negate.isVariable);
-  Expect.isTrue(operator_negate.isMethod);
   Expect.isFalse(operator_negate.isPrivate);
   Expect.isFalse(operator_negate.isStatic);
-  Expect.isTrue(operator_negate is MethodMirror);
   Expect.isTrue(operator_negate.isRegularMethod);
   Expect.isFalse(operator_negate.isConstConstructor);
   Expect.isFalse(operator_negate.isGenerativeConstructor);
@@ -899,16 +836,10 @@
   Expect.isTrue(operator_negate.isOperator);
   Expect.stringEquals('-', operatorName(operator_negate));
 
-
-  var bazClassConstructors = bazClass.constructors;
-  Expect.isNotNull(bazClassConstructors, "Constructors map is null");
-  Expect.equals(3, bazClassConstructors.length,
-                "Unexpected number of constructors");
-
   ////////////////////////////////////////////////////////////////////////////
   //   Baz();
   ////////////////////////////////////////////////////////////////////////////
-  var bazClassNonameConstructor = bazClassConstructors[''];
+  var bazClassNonameConstructor = bazClassMembers[const Symbol('')];
   Expect.isNotNull(bazClassNonameConstructor);
   Expect.isTrue(bazClassNonameConstructor is MethodMirror);
   Expect.isTrue(bazClassNonameConstructor.isConstructor);
@@ -917,15 +848,15 @@
   Expect.isTrue(bazClassNonameConstructor.isGenerativeConstructor);
   Expect.isFalse(bazClassNonameConstructor.isRedirectingConstructor);
   Expect.isFalse(bazClassNonameConstructor.isFactoryConstructor);
-  Expect.stringEquals('', bazClassNonameConstructor.simpleName);
+  Expect.equals(const Symbol(''), bazClassNonameConstructor.simpleName);
   Expect.stringEquals('Baz', displayName(bazClassNonameConstructor));
-  Expect.stringEquals('mirrors_helper.Baz.',
+  Expect.equals(const Symbol('mirrors_helper.Baz.'),
       bazClassNonameConstructor.qualifiedName);
 
   ////////////////////////////////////////////////////////////////////////////
   //   const Baz.named();
   ////////////////////////////////////////////////////////////////////////////
-  var bazClassNamedConstructor = bazClassConstructors['named'];
+  var bazClassNamedConstructor = bazClassMembers[#named];
   Expect.isNotNull(bazClassNamedConstructor);
   Expect.isTrue(bazClassNamedConstructor is MethodMirror);
   Expect.isTrue(bazClassNamedConstructor.isConstructor);
@@ -934,15 +865,15 @@
   Expect.isFalse(bazClassNamedConstructor.isGenerativeConstructor);
   Expect.isFalse(bazClassNamedConstructor.isRedirectingConstructor);
   Expect.isFalse(bazClassNamedConstructor.isFactoryConstructor);
-  Expect.stringEquals('named', bazClassNamedConstructor.simpleName);
+  Expect.equals(#named, bazClassNamedConstructor.simpleName);
   Expect.stringEquals('Baz.named', displayName(bazClassNamedConstructor));
-  Expect.stringEquals('mirrors_helper.Baz.named',
+  Expect.equals(#mirrors_helper.Baz.named,
       bazClassNamedConstructor.qualifiedName);
 
   ////////////////////////////////////////////////////////////////////////////
   //   factory Baz.factory() => new Baz<E,F>();
   ////////////////////////////////////////////////////////////////////////////
-  var bazClassFactoryConstructor = bazClassConstructors['factory'];
+  var bazClassFactoryConstructor = bazClassMembers[#factory];
   Expect.isNotNull(bazClassFactoryConstructor);
   Expect.isTrue(bazClassFactoryConstructor is MethodMirror);
   Expect.isTrue(bazClassFactoryConstructor.isConstructor);
@@ -951,9 +882,9 @@
   Expect.isFalse(bazClassFactoryConstructor.isGenerativeConstructor);
   Expect.isFalse(bazClassFactoryConstructor.isRedirectingConstructor);
   Expect.isTrue(bazClassFactoryConstructor.isFactoryConstructor);
-  Expect.stringEquals('factory', bazClassFactoryConstructor.simpleName);
+  Expect.equals(#factory, bazClassFactoryConstructor.simpleName);
   Expect.stringEquals('Baz.factory', displayName(bazClassFactoryConstructor));
-  Expect.stringEquals('mirrors_helper.Baz.factory',
+  Expect.equals(#mirrors_helper.Baz.factory,
       bazClassFactoryConstructor.qualifiedName);
 
   // TODO(johnniwinther): Add more tests of constructors.
@@ -973,41 +904,41 @@
 //   factory _PrivateClass._privateFactoryConstructor() => new _PrivateClass();
 // }
 void testPrivate(MirrorSystem system, LibraryMirror helperLibrary,
-                 Map<String,TypeMirror> classes) {
-  var privateClass = classes['_PrivateClass'];
+                 Map<Symbol, DeclarationMirror> declarations) {
+  var privateClass = declarations[const Symbol('_PrivateClass')];
   Expect.isNotNull(privateClass);
   Expect.isTrue(privateClass is ClassMirror);
-  Expect.isTrue(privateClass.isClass);
   Expect.isFalse(privateClass.isAbstract);
   Expect.isTrue(privateClass.isPrivate);
 
-  var privateField = privateClass.members['_privateField'];
+  var privateField = privateClass.declarations[const Symbol('_privateField')];
   Expect.isNotNull(privateField);
   Expect.isTrue(privateField is VariableMirror);
   Expect.isTrue(privateField.isPrivate);
 
-  var privateGetter = privateClass.members['_privateGetter'];
+  var privateGetter = privateClass.declarations[const Symbol('_privateGetter')];
   Expect.isNotNull(privateGetter);
   Expect.isTrue(privateGetter is MethodMirror);
   Expect.isTrue(privateGetter.isGetter);
   Expect.isTrue(privateGetter.isPrivate);
   Expect.isFalse(privateGetter.isRegularMethod);
 
-  var privateSetter = privateClass.members['_privateSetter='];
+  var privateSetter =
+      privateClass.declarations[const Symbol('_privateSetter=')];
   Expect.isNotNull(privateSetter);
   Expect.isTrue(privateSetter is MethodMirror);
   Expect.isTrue(privateSetter.isSetter);
   Expect.isTrue(privateSetter.isPrivate);
   Expect.isFalse(privateSetter.isRegularMethod);
 
-  var privateMethod = privateClass.members['_privateMethod'];
+  var privateMethod = privateClass.declarations[const Symbol('_privateMethod')];
   Expect.isNotNull(privateMethod);
   Expect.isTrue(privateMethod is MethodMirror);
   Expect.isTrue(privateMethod.isPrivate);
   Expect.isTrue(privateMethod.isRegularMethod);
 
   var privateConstructor =
-      privateClass.members['_privateConstructor'];
+      privateClass.declarations[const Symbol('_privateConstructor')];
   Expect.isNotNull(privateConstructor);
   Expect.isTrue(privateConstructor is MethodMirror);
   Expect.isTrue(privateConstructor.isConstructor);
@@ -1018,7 +949,7 @@
   Expect.isFalse(privateConstructor.isFactoryConstructor);
 
   var privateFactoryConstructor =
-      privateClass.members['_privateFactoryConstructor'];
+      privateClass.declarations[const Symbol('_privateFactoryConstructor')];
   Expect.isNotNull(privateFactoryConstructor);
   Expect.isTrue(privateFactoryConstructor is MethodMirror);
   Expect.isTrue(privateFactoryConstructor.isConstructor);
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index b63df94..eca7e6f 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -237,6 +237,8 @@
   List<WarningMessage> errors;
   List<WarningMessage> hints;
   List<WarningMessage> infos;
+  final bool allowWarnings;
+  final bool allowErrors;
   final Map<String, SourceFile> sourceFiles;
   Node parsedTree;
 
@@ -255,7 +257,9 @@
                 bool preserveComments: false,
                 // Our unit tests check code generation output that is
                 // affected by inlining support.
-                bool disableInlining: true})
+                bool disableInlining: true,
+                bool this.allowWarnings: true,
+                bool this.allowErrors: true})
       : warnings = [], errors = [], hints = [], infos = [],
         sourceFiles = new Map<String, SourceFile>(),
         super(enableTypeAssertions: enableTypeAssertions,
@@ -299,6 +303,18 @@
     deferredLoadTask = new MockDeferredLoadTask(this);
   }
 
+  Future runCompiler(Uri uri) {
+    return super.runCompiler(uri).then((result) {
+      if (!allowErrors && !errors.isEmpty) {
+        throw "unexpected error during compilation ${errors}";
+      } else if (!allowWarnings && !warnings.isEmpty) {
+        throw "unexpected warnings during compilation ${warnings}";
+      } else {
+        return result;
+      }
+    });
+  }
+
   /**
    * Registers the [source] with [uri] making it possible load [source] as a
    * library.
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart
new file mode 100644
index 0000000..d8bdeb3
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure2_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) {  // Called via [foo] with integer then double.
+  return a;
+}
+
+const foo = method;
+
+returnNum(x) {
+  return foo(x);
+}
+
+main() {
+  returnNum(10);
+  returnNum(10.5);
+}
+""";
+
+
+void main() {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(TEST, uri);
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var typesInferrer = compiler.typesTask.typesInferrer;
+
+    checkReturn(String name, type) {
+      var element = findElement(compiler, name);
+      Expect.equals(type,
+          typesInferrer.getReturnTypeOfElement(element).simplify(compiler),
+          name);
+    }
+
+    checkReturn('method', compiler.typesTask.numType);
+    checkReturn('returnNum', compiler.typesTask.numType);
+  }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart
new file mode 100644
index 0000000..184229a
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure3_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) {  // Called only via [foo2] with a small integer.
+  return a;
+}
+
+const foo = method;
+
+returnInt() {
+  return foo(54);
+}
+
+main() {
+  returnInt();
+}
+""";
+
+
+void main() {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(TEST, uri);
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var typesInferrer = compiler.typesTask.typesInferrer;
+
+    checkArgument(String functionName, type) {
+      var functionElement = findElement(compiler, functionName);
+      var signature = functionElement.functionSignature;
+      var element = signature.requiredParameters.first;
+      Expect.equals(type,
+          typesInferrer.getTypeOfElement(element).simplify(compiler),
+          functionName);
+    }
+
+    checkArgument('method', compiler.typesTask.uint31Type);
+  }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart
new file mode 100644
index 0000000..36c988d
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure4_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) {  // Called via [foo] with integer then double.
+  return a;
+}
+
+const foo = method;
+
+returnNum(x) {
+  return foo(x);
+}
+
+main() {
+  returnNum(10);
+  returnNum(10.5);
+}
+""";
+
+
+void main() {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(TEST, uri);
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var typesInferrer = compiler.typesTask.typesInferrer;
+
+    checkArgument(String functionName, type) {
+      var functionElement = findElement(compiler, functionName);
+      var signature = functionElement.functionSignature;
+      var element = signature.requiredParameters.first;
+      Expect.equals(type,
+          typesInferrer.getTypeOfElement(element).simplify(compiler),
+          functionName);
+    }
+
+    checkArgument('method', compiler.typesTask.numType);
+    checkArgument('returnNum', compiler.typesTask.numType);
+  }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart
new file mode 100644
index 0000000..46b4e83
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure5_test.dart
@@ -0,0 +1,45 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) {  // Called only via [foo2] with a small integer.
+  return a;
+}
+
+const foo = method;
+
+returnInt() {
+  return foo(54);
+}
+
+main() {
+  returnInt();
+  method(55.2);
+}
+""";
+
+
+void main() {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(TEST, uri);
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var typesInferrer = compiler.typesTask.typesInferrer;
+
+    checkArgument(String functionName, type) {
+      var functionElement = findElement(compiler, functionName);
+      var signature = functionElement.functionSignature;
+      var element = signature.requiredParameters.first;
+      Expect.equals(type,
+          typesInferrer.getTypeOfElement(element).simplify(compiler),
+          functionName);
+    }
+
+    checkArgument('method', compiler.typesTask.numType);
+  }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart
new file mode 100644
index 0000000..7b7be1a
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_const_closure_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method1() {
+  return 42;
+}
+
+method2(a) {  // Called only via [foo2] with a small integer.
+  return a;
+}
+
+const foo1 = method1;
+const foo2 = method2;
+
+returnInt1() {
+  return foo1();
+}
+
+returnInt2() {
+  return foo2(54);
+}
+
+main() {
+  returnInt1();
+  returnInt2();
+}
+""";
+
+
+void main() {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(TEST, uri);
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var typesInferrer = compiler.typesTask.typesInferrer;
+
+    checkReturn(String name, type) {
+      var element = findElement(compiler, name);
+      Expect.equals(type,
+          typesInferrer.getReturnTypeOfElement(element).simplify(compiler),
+          name);
+    }
+
+    checkReturn('method1', compiler.typesTask.uint31Type);
+    checkReturn('returnInt1', compiler.typesTask.uint31Type);
+
+    checkReturn('method2', compiler.typesTask.uint31Type);
+    checkReturn('returnInt2', compiler.typesTask.uint31Type);
+  }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart b/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart
new file mode 100644
index 0000000..0b9510e
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_global_field_closure2_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method(a) {  // Called only via [foo] with a small integer.
+  return a;
+}
+
+var foo = method;
+
+returnInt() {
+  return foo(54);
+}
+
+main() {
+  returnInt();
+}
+""";
+
+
+void main() {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(TEST, uri);
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var typesInferrer = compiler.typesTask.typesInferrer;
+
+    checkArgument(String functionName, type) {
+      var functionElement = findElement(compiler, functionName);
+      var signature = functionElement.functionSignature;
+      var element = signature.requiredParameters.first;
+      Expect.equals(type,
+          typesInferrer.getTypeOfElement(element).simplify(compiler),
+          functionName);
+    }
+
+    checkArgument('method', compiler.typesTask.uint31Type);
+  }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart b/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart
new file mode 100644
index 0000000..fcfa00c9
--- /dev/null
+++ b/tests/compiler/dart2js/simple_inferrer_global_field_closure_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+import 'compiler_helper.dart';
+
+const String TEST = """
+
+method1() {
+  return 42;
+}
+
+method2(a) {  // Called only via [foo2] with a small integer.
+  return a;
+}
+
+var foo1 = method1;
+var foo2 = method2;
+
+returnInt1() {
+  return foo1();
+}
+
+returnInt2() {
+  return foo2(54);
+}
+
+main() {
+  returnInt1();
+  returnInt2();
+}
+""";
+
+
+void main() {
+  Uri uri = new Uri(scheme: 'source');
+  var compiler = compilerFor(TEST, uri);
+  asyncTest(() => compiler.runCompiler(uri).then((_) {
+    var typesInferrer = compiler.typesTask.typesInferrer;
+
+    checkReturn(String name, type) {
+      var element = findElement(compiler, name);
+      Expect.equals(type,
+          typesInferrer.getReturnTypeOfElement(element).simplify(compiler),
+          name);
+    }
+
+    checkReturn('method1', compiler.typesTask.uint31Type);
+    checkReturn('returnInt1', compiler.typesTask.uint31Type);
+
+    checkReturn('method2', compiler.typesTask.uint31Type);
+    checkReturn('returnInt2', compiler.typesTask.uint31Type);
+  }));
+}
diff --git a/tests/compiler/dart2js/unparser_test.dart b/tests/compiler/dart2js/unparser_test.dart
index e978f80..5409768 100644
--- a/tests/compiler/dart2js/unparser_test.dart
+++ b/tests/compiler/dart2js/unparser_test.dart
@@ -337,6 +337,8 @@
        //"int this.baz(a)", // Commented out due to Issue 7852
        //"int this.boz(int a,int b)=null" // Commented out due to Issue 7852
        ]);
+  testUnparseParameters(
+      ["@a foo", "@b @c bar=0", "@D(0) int baz", "@E([f],{g:h}) int boz=0"]);
 }
 
 testSymbolLiterals() {
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index 55294d8..504e89f 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -11,6 +11,9 @@
 deferred/deferred_constant_test: Fail # http://dartbug.com/11138
 constant_javascript_semantics4_test: Fail, OK
 
+[ $compiler == dart2js && $runtime == jsshell ]
+mirror_printer_test: Pass, Slow # Issue 16473
+
 [ $compiler == dart2js && $checked ]
 variable_type_test/03: Fail, OK
 variable_type_test/01: Fail, OK
diff --git a/tests/html/events_test.dart b/tests/html/events_test.dart
index ebb9181..3b87540 100644
--- a/tests/html/events_test.dart
+++ b/tests/html/events_test.dart
@@ -71,7 +71,16 @@
     provider.forTarget(element).listen(handler);
     invocationCounter = 0;
     element.dispatchEvent(event);
-    expect(invocationCounter, 1);
+
+    // NOTE: when run in a custom zone, the handler is wrapped
+    // The logic for html events which ensures identical handlers are added only
+    // once is therefor muted by the wrapped handlers.
+    // Hence, we get different behavior depending on the current zone.
+    if(Zone.current == Zone.ROOT) {
+      expect(invocationCounter, 1);
+    } else {
+      expect(invocationCounter, 2);
+    }
   });
 
   test('InitMouseEvent', () {
diff --git a/tests/html/html.status b/tests/html/html.status
index 0e256b0..26672d0 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -67,7 +67,6 @@
 async_test: Pass, Fail # timers test fails on ie10.
 indexeddb_5_test: Fail # Issue 12893
 js_test: Fail # Issue 14246
-custom/constructor_calls_created_synchronously_test: Fail, Pass # Issue 16453
 
 [ $compiler == dart2js && ( $runtime == ie9 || $runtime == ie10 ) ]
 worker_api_test: Fail # IE does not support URL.createObjectURL in web workers.
@@ -174,9 +173,6 @@
 xhr_cross_origin_test: Skip # Issue 12920
 xhr_test/json: Fail # IE9 returns null because of unsupported type
 js_test: RuntimeError # Issue 14645
-custom/mirrors_test: pass, fail # Issue 16441
-custom/constructor_calls_created_synchronously_test: pass, fail # Issue 16441
-custom/document_register_basic_test: pass, fail # Issue 16455
 
 # IE9 Feature support statuses-
 # All changes should be accompanied by platform support annotation changes.
diff --git a/tests/html/js_test.dart b/tests/html/js_test.dart
index 3d58e2d..ba5d007 100644
--- a/tests/html/js_test.dart
+++ b/tests/html/js_test.dart
@@ -186,6 +186,10 @@
   return o1 === o2;
 }
 
+var someProto = { role: "proto" };
+var someObject = Object.create(someProto);
+someObject.role = "object";
+
 """;
   document.body.append(script);
 }
@@ -286,6 +290,17 @@
       context.deleteProperty('obj');
     });
 
+    group('caching', () {
+      test('JS->Dart', () {
+        // Test that we are not pulling cached proxy from the prototype
+        // when asking for a proxy for the object.
+        final proto = context['someProto'];
+        expect(proto['role'], equals('proto'));
+        final obj = context['someObject'];
+        expect(obj['role'], equals('object'));
+      });
+    });
+
   });
 
   group('context', () {
@@ -995,4 +1010,5 @@
 
     });
   });
+
 }
diff --git a/tests/html/utils.dart b/tests/html/utils.dart
index 6e5010e..9b469b1 100644
--- a/tests/html/utils.dart
+++ b/tests/html/utils.dart
@@ -163,11 +163,6 @@
 
 Future loadCustomElementPolyfill() {
   if (!document.supportsRegister) {
-    if (!MutationObserver.supported) {
-      var script = new ScriptElement()
-          ..src = '/packages/mutation_observer/mutation_observer.js';
-      document.head.append(script);
-    }
     var script = new ScriptElement()
         ..src = '/packages/custom_element/custom-elements.debug.js';
     document.head.append(script);
diff --git a/tests/isolate/capability_test.dart b/tests/isolate/capability_test.dart
new file mode 100644
index 0000000..a9d3ae6
--- /dev/null
+++ b/tests/isolate/capability_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2014, 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.
+
+import "dart:isolate";
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+void main() {
+  asyncStart();
+  var c1 = new Capability();
+  var c2 = new Capability();
+  Expect.notEquals(c1, c2);
+
+  var receive = new RawReceivePort();
+  receive.sendPort.send(c1);
+  receive.handler = (c3) {
+    Expect.equals(c3, c1);
+    Expect.notEquals(c3, c2);
+    asyncEnd();
+  };
+}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 0df05ed2..a753ec2 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -6,10 +6,12 @@
 browser/*: SkipByDesign  # Browser specific tests
 isolate_stress_test: Fail # Issue 12588: This should be able to pass when we have wrapper-less tests.
 
-[ $compiler == none ]
+[ $compiler == none || $compiler == dart2dart ]
 serialization_test: SkipByDesign # Tests dart2js-specific serialization code
 isolate_throws_test/01: Skip # Issue 12587
 compile_time_error_test/01: Skip # Issue 12587
+capability_test: Fail  # Not implemented yet
+pause_test: Fail
 
 [ $compiler == dart2js && $jscl ]
 browser/*: SkipByDesign  # Browser specific tests
@@ -19,6 +21,7 @@
 
 [ $compiler == dart2js ]
 serialization_test: RuntimeError # Issue 1882, tries to access class TestingOnly declared in isolate_patch.dart
+pause_test: Fail
 
 [ $compiler == dart2js && $runtime == ie9 ]
 browser/typed_data_message_test: Fail # Issue 12624
@@ -39,8 +42,6 @@
 
 [ $compiler == dart2js && $runtime == none ]
 serialization_test: Pass # Issue 12628
-illegal_msg_function_test: Pass # Issue 12628
-illegal_msg_mirror_test: Pass # Issue 12628
 
 [ $compiler == dart2js && $runtime == chromeOnAndroid ]
 isolate_stress_test: Pass, Slow # TODO(kasperl): Please triage.
@@ -48,7 +49,11 @@
 mandel_isolate_test: Pass, Timeout # TODO(kasperl): Please triage.
 
 [ $compiler == dart2dart ]
-*: Skip # Issue 12629
+illegal_msg_mirror_test: RuntimeError    # Issue 16548
+spawn_uri_multi_test/none: RuntimeError  # Issue 16549
+spawn_uri_nested_vm_test: RuntimeError   # Issue 16549
+spawn_uri_test: RuntimeError             # Issue 16549
+spawn_uri_vm_test: RuntimeError          # Issue 16549
 
 [ $compiler == dart2js && ( $runtime == ff || $runtime == safari || $runtime == drt || $runtime == chrome || $runtime == chromeOnAndroid) ]
 isolate_stress_test: Pass, Slow # Issue 10697
diff --git a/tests/isolate/pause_test.dart b/tests/isolate/pause_test.dart
new file mode 100644
index 0000000..71691ad
--- /dev/null
+++ b/tests/isolate/pause_test.dart
@@ -0,0 +1,44 @@
+// Copyright (c) 2014, 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.
+
+import "dart:isolate";
+import "dart:async";
+import "package:async_helper/async_helper.dart";
+
+isomain1(replyPort) {
+  RawReceivePort port = new RawReceivePort();
+  port.handler = (v) {
+    replyPort.send(v);
+    port.close();
+  };
+  replyPort.send(port.sendPort);
+}
+
+main(){
+  asyncStart();
+  RawReceivePort reply = new RawReceivePort();
+  Isolate isolate;
+  Capability resume;
+  var completer = new Completer();  // Completed by first reply from isolate.
+  reply.handler = completer.complete;
+  Isolate.spawn(isomain1, reply.sendPort).then((Isolate iso) {
+    isolate = iso;
+    resume = isolate.pause();
+    return completer.future;
+  }).then((echoPort) {
+    // Isolate has been created, and first response has been returned.
+    echoPort.send(24);
+    reply.handler = (v) {
+      throw "RESPONSE WHILE PAUSED?!?";
+    };
+    return new Future.delayed(const Duration(milliseconds: 250));
+  }).then((_) {
+    reply.handler = (v) {
+      if (v != 24) throw "WRONG ANSWER!";
+      reply.close();
+      asyncEnd();
+    };
+    isolate.resume(resume);
+  });
+}
diff --git a/tests/language/arithmetic_test.dart b/tests/language/arithmetic_test.dart
index 64ab133..b660960 100644
--- a/tests/language/arithmetic_test.dart
+++ b/tests/language/arithmetic_test.dart
@@ -449,6 +449,14 @@
     Expect.approxEquals(1.0, sinCosSub(3.14159265 / 2.0));
   }
 
+  // Test fix for issue 16592.
+  static void testSinCosNoUse() {
+    for (var i = 0; i < 20; i++) {
+      sin(i);
+      cos(i);
+    }
+  }
+    
   static mySqrt(var x) => sqrt(x);
 
   static testSqrtDeopt() {
@@ -477,6 +485,7 @@
       testSqrtDeopt();
       testDoubleEquality();
       testSinCos();
+      testSinCosNoUse();
     }
   }
 }
diff --git a/tests/language/function_propagation_test.dart b/tests/language/function_propagation_test.dart
new file mode 100644
index 0000000..afb4a1c
--- /dev/null
+++ b/tests/language/function_propagation_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2014, 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.
+
+import "package:expect/expect.dart";
+
+class A {
+  int call(String str) => 499;
+}
+
+typedef int F(String str);
+
+main() {
+  var a = new A();
+  if (a is Function) {
+    Expect.isTrue(a is A);
+  } else {
+    Expect.fail("a should be a Function");
+  }
+
+  var a2 = new A();
+  if (a2 is F) {
+    Expect.isTrue(a2 is A);
+  } else {
+    Expect.fail("a2 should be an F");
+  }
+
+  Function a3 = new A();
+  // Dart2Js mistakenly assumed that Function and A couldn't be related and
+  // returned false for a is A.
+  Expect.isTrue(a3 is A);
+
+  F a4 = new A();
+  Expect.isTrue(a4 is A);
+}
diff --git a/tests/language/function_type_call_getter2_test.dart b/tests/language/function_type_call_getter2_test.dart
new file mode 100644
index 0000000..2d27ea8
--- /dev/null
+++ b/tests/language/function_type_call_getter2_test.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2014, 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.
+
+import "package:expect/expect.dart";
+
+class A {
+  final call = null;
+}
+
+class B {
+  get call => null;
+}
+
+class C {
+  set call(x) {}
+}
+
+typedef int F(String str);
+
+main() {
+  A a = new A();
+  B b = new B();
+  C c = new C();
+
+  final
+  Function  /// 00: static type warning, dynamic type error
+  a2 = a;
+
+  final
+  F  /// 01: static type warning, dynamic type error
+  a3 = a;
+
+  final
+  Function  /// 02: static type warning, dynamic type error
+  b2 = b;
+
+  final
+  F  /// 03: static type warning, dynamic type error
+  b3 = b;
+
+  final
+  Function  /// 04: static type warning, dynamic type error
+  c2 = c;
+
+  final
+  F  /// 05: static type warning, dynamic type error
+  c3 = c;
+}
diff --git a/tests/language/function_type_call_getter_test.dart b/tests/language/function_type_call_getter_test.dart
new file mode 100644
index 0000000..52ecbaa
--- /dev/null
+++ b/tests/language/function_type_call_getter_test.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2014, 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.
+
+import "package:expect/expect.dart";
+
+class A {
+  final call = null;
+}
+
+class B {
+  get call => null;
+}
+
+class C {
+  set call(x) {}
+}
+
+typedef int F(String str);
+
+main() {
+  Expect.isFalse(new A() is Function);
+  Expect.isFalse(new B() is Function);
+  Expect.isFalse(new C() is Function);
+  Expect.isFalse(new A() is F);
+  Expect.isFalse(new B() is F);
+  Expect.isFalse(new C() is F);
+}
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index e86eaa7..c48c244 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -24,7 +24,7 @@
 assignable_expression_test/32: Fail # Issue 15471
 assignable_expression_test/42: Fail # Issue 15471
 
-#unicode_bom_test: Fail # Issue 16314
+unicode_bom_test: Fail # Issue 16314
 
 # Please add new failing tests before this line.
 # Section below is for invalid tests.
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index 2f847f5..e2ec9f3 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -6,35 +6,31 @@
 lib/_internal: Skip # Slow like a hell - timeouts.
 
 [ $compiler == dartanalyzer || $compiler == dart2analyzer ]
-lib/_chrome/dart2js/chrome_dart2js: CompileTimeError
-lib/html/dart2js/html_dart2js: CompileTimeError
-lib/html/dartium/html_dartium: CompileTimeError
-lib/html/html_common/html_common: CompileTimeError
-lib/html/html_common/html_common_dart2js: CompileTimeError
-lib/indexed_db/dart2js/indexed_db_dart2js: CompileTimeError
-lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError
-lib/_internal/compiler/samples/compile_loop/compile_loop: CompileTimeError
-lib/_internal/compiler/samples/darttags/darttags: CompileTimeError
-lib/_internal/compiler/samples/leap/leap: CompileTimeError
-lib/_internal/compiler/samples/leap/leap_leg: CompileTimeError
-lib/_internal/compiler/samples/leap/request_cache: CompileTimeError
-lib/_internal/dartdoc/bin/dartdoc: CompileTimeError
-lib/_internal/dartdoc/lib/dartdoc: CompileTimeError
-lib/_internal/dartdoc/lib/src/client/client-live-nav: CompileTimeError
-lib/_internal/dartdoc/lib/src/client/client-shared: CompileTimeError
-lib/_internal/dartdoc/lib/src/client/dropdown: CompileTimeError
-lib/_internal/dartdoc/lib/src/client/search: CompileTimeError
-lib/_internal/dartdoc/lib/universe_serializer: CompileTimeError
-lib/_internal/pub/lib/src/command: Pass, CompileTimeError # Pass necessary, since CompileTimeError is valid for everything in that directory (not only for src/command.dart)
-lib/js/dart2js/js_dart2js: CompileTimeError
-lib/js/dartium/js_dartium: CompileTimeError
-lib/svg/dart2js/svg_dart2js: CompileTimeError
-lib/svg/dartium/svg_dartium: CompileTimeError
-lib/typed_data/dart2js/native_typed_data_dart2js: CompileTimeError
-lib/typed_data/dart2js/typed_data_dart2js: CompileTimeError
-lib/web_audio/dart2js/web_audio_dart2js: CompileTimeError
-lib/web_audio/dartium/web_audio_dartium: CompileTimeError
-lib/web_gl/dart2js/web_gl_dart2js: CompileTimeError
-lib/web_gl/dartium/web_gl_dartium: CompileTimeError
-lib/web_sql/dart2js/web_sql_dart2js: CompileTimeError
-lib/web_sql/dartium/web_sql_dartium: CompileTimeError
+lib/_chrome/dart2js/chrome_dart2js: CompileTimeError # Issue 16522
+lib/html/dart2js/html_dart2js: CompileTimeError # Issue 16522
+lib/html/dartium/html_dartium: CompileTimeError # Issue 16522
+lib/html/html_common/html_common: CompileTimeError # Issue 16522
+lib/html/html_common/html_common_dart2js: CompileTimeError # Issue 16522
+lib/indexed_db/dart2js/indexed_db_dart2js: CompileTimeError # Issue 16524
+lib/indexed_db/dartium/indexed_db_dartium: CompileTimeError # Issue 16524
+lib/_internal/compiler/samples/compile_loop/compile_loop: CompileTimeError  # Issue 16524
+lib/_internal/compiler/samples/darttags/darttags: CompileTimeError  # Issue 16524
+lib/js/dart2js/js_dart2js: CompileTimeError # Issue 16524
+lib/js/dartium/js_dartium: CompileTimeError # Issue 16524
+lib/svg/dart2js/svg_dart2js: CompileTimeError # Issue 16524
+lib/svg/dartium/svg_dartium: CompileTimeError # Issue 16524
+lib/typed_data/dart2js/native_typed_data_dart2js: CompileTimeError # Issue 16524
+lib/typed_data/dart2js/typed_data_dart2js: CompileTimeError # Issue 16524
+lib/web_audio/dart2js/web_audio_dart2js: CompileTimeError # Issue 16524
+lib/web_audio/dartium/web_audio_dartium: CompileTimeError # Issue 16524
+lib/web_gl/dart2js/web_gl_dart2js: CompileTimeError # Issue 16524
+lib/web_gl/dartium/web_gl_dartium: CompileTimeError # Issue 16524
+lib/web_sql/dart2js/web_sql_dart2js: CompileTimeError # Issue 16524
+lib/web_sql/dartium/web_sql_dartium: CompileTimeError # Issue 16524
+lib/_internal/compiler/samples/jsonify/jsonify: CompileTimeError # issue 16466
+lib/_internal/compiler/implementation/mirrors/analyze: CompileTimeError # issue 16466
+lib/_internal/compiler/implementation/mirrors/dart2js_mirrors: CompileTimeError # issue 16466
+
+# Pass necessary, since CompileTimeError is valid for everything in that
+# directory (not only for src/command.dart)
+lib/_internal/pub/lib/src/command: Pass, CompileTimeError
diff --git a/tests/lib/async/future_timeout_test.dart b/tests/lib/async/future_timeout_test.dart
index cd30645..d81c87f 100644
--- a/tests/lib/async/future_timeout_test.dart
+++ b/tests/lib/async/future_timeout_test.dart
@@ -142,6 +142,7 @@
   });
 
   test("timeoutZone", () {
+    var initialZone = Zone.current;
     Zone forked;
     int registerCallDelta = 0;
     bool callbackCalled = false;
@@ -169,7 +170,7 @@
     timedOut.then(expectAsync1((v) {
       expect(callbackCalled, true);
       expect(registerCallDelta, 0);
-      expect(Zone.current, Zone.ROOT);
+      expect(Zone.current, initialZone);
       expect(v, 42);
     }));
   });
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index cf8e1f6..986be7e 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -68,12 +68,13 @@
 mirrors/method_mirror_name_test: RuntimeError # Issue 6335
 mirrors/method_mirror_properties_test: RuntimeError # Issue 11861
 mirrors/method_mirror_source_test : RuntimeError # Issue 6490
+mirrors/method_mirror_source_line_ending_test : RuntimeError # Issue 6490
 mirrors/mirrors_test: RuntimeError # TODO(ahe): I'm working on fixing this.
 mirrors/mixin_test: RuntimeError # Issue 12464
 mirrors/mixin_application_test/none: RuntimeError # Issue 12464
 mirrors/null_test : RuntimeError # Issue 12129
 mirrors/parameter_test/none: RuntimeError # Issue 6490
-mirrors/parameter_metadata_test: CompileTimeError # Issue 10905
+mirrors/parameter_metadata_test: RuntimeError # Issue 10905
 mirrors/private_symbol_test: CompileTimeError # Issue 13597
 mirrors/proxy_type_test: RuntimeError # Issue 13842
 mirrors/redirecting_factory_test/none: RuntimeError # Issue 6490
@@ -91,6 +92,7 @@
 mirrors/variable_is_const_test/01: MissingCompileTimeError # Issue 5519
 mirrors/list_constructor_test/01: RuntimeError # Issue 13523
 mirrors/raw_type_test/01: RuntimeError # http://dartbug.com/6490
+mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16589
 
 [ $runtime == safari ]
 typed_data/setRange_2_test: Fail # Safari doesn't fully implement spec for TypedArray.set
@@ -197,6 +199,7 @@
 convert/utf85_test: Skip # Issue 12029.
 async/timer_isolate_test: Pass, Fail # Issue 14734
 convert/json_util_test: Fail # Issue 16109
+mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16589
 
 [ $compiler == dart2js ]
 typed_data/typed_data_hierarchy_int64_test: RuntimeError # Issue 10275
@@ -226,6 +229,15 @@
 
 async/timer_not_available_test: SkipByDesign # only meant to test when there is no way to implement timer (currently only in d8)
 
+[ $compiler == none ]
+mirrors/mirrors_reader_test: Slow, Pass
+
+[ $compiler == none && $checked ]
+mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16588
+
+[ $compiler == none && $runtime == dartium ]
+mirrors/mirrors_reader_test: Slow, RuntimeError # Issue 16626
+
 [ $compiler == none && ( $runtime == drt || $runtime == dartium ) ]
 async/schedule_microtask6_test: Fail # Issue 10910
 mirrors/immutable_collections_test: Pass, Slow # Dartium debug uses -O0
diff --git a/tests/lib/math/random_test.dart b/tests/lib/math/random_test.dart
index 28cf084..f769efb 100644
--- a/tests/lib/math/random_test.dart
+++ b/tests/lib/math/random_test.dart
@@ -11,50 +11,91 @@
 import 'dart:math';
 
 main() {
+  checkSequence();
+  checkSeed();
+}
+
+void checkSequence() {
+  // Check the sequence of numbers generated by the random generator for a seed
+  // doesn't change unintendedly, and it agrees between implementations.
   var rnd = new Random(20130307);
   // Make sure we do not break the random number generation.
   // If the random algorithm changes, make sure both the VM and dart2js
   // generate the same new sequence.
   var i = 1;
-  Expect.equals(         1, rnd.nextInt(i *= 2));
-  Expect.equals(         1, rnd.nextInt(i *= 2));
+  Expect.equals(         0, rnd.nextInt(i *= 2));
+  Expect.equals(         3, rnd.nextInt(i *= 2));
   Expect.equals(         7, rnd.nextInt(i *= 2));
-  Expect.equals(         6, rnd.nextInt(i *= 2));
-  Expect.equals(         6, rnd.nextInt(i *= 2));
-  Expect.equals(        59, rnd.nextInt(i *= 2));
-  Expect.equals(        11, rnd.nextInt(i *= 2));
-  Expect.equals(       212, rnd.nextInt(i *= 2));
+  Expect.equals(         5, rnd.nextInt(i *= 2));
+  Expect.equals(        29, rnd.nextInt(i *= 2));
   Expect.equals(        17, rnd.nextInt(i *= 2));
-  Expect.equals(       507, rnd.nextInt(i *= 2));
-  Expect.equals(      1060, rnd.nextInt(i *= 2));
-  Expect.equals(       891, rnd.nextInt(i *= 2));
-  Expect.equals(      1534, rnd.nextInt(i *= 2));
-  Expect.equals(      8404, rnd.nextInt(i *= 2));
-  Expect.equals(     13839, rnd.nextInt(i *= 2));
-  Expect.equals(     23298, rnd.nextInt(i *= 2));
-  Expect.equals(     53622, rnd.nextInt(i *= 2));
-  Expect.equals(    205997, rnd.nextInt(i *= 2));
-  Expect.equals(    393823, rnd.nextInt(i *= 2));
-  Expect.equals(    514614, rnd.nextInt(i *= 2));
-  Expect.equals(    233715, rnd.nextInt(i *= 2));
-  Expect.equals(    895357, rnd.nextInt(i *= 2));
-  Expect.equals(   4726185, rnd.nextInt(i *= 2));
-  Expect.equals(   7976427, rnd.nextInt(i *= 2));
-  Expect.equals(  31792146, rnd.nextInt(i *= 2));
-  Expect.equals(  35563210, rnd.nextInt(i *= 2));
-  Expect.equals( 113261265, rnd.nextInt(i *= 2));
-  Expect.equals( 205117298, rnd.nextInt(i *= 2));
-  Expect.equals( 447729735, rnd.nextInt(i *= 2));
-  Expect.equals(1072507596, rnd.nextInt(i *= 2));
-  Expect.equals(2134030067, rnd.nextInt(i *= 2));
-  Expect.equals( 721180690, rnd.nextInt(i *= 2));
+  Expect.equals(       104, rnd.nextInt(i *= 2));
+  Expect.equals(       199, rnd.nextInt(i *= 2));
+  Expect.equals(       408, rnd.nextInt(i *= 2));
+  Expect.equals(       362, rnd.nextInt(i *= 2));
+  Expect.equals(       995, rnd.nextInt(i *= 2));
+  Expect.equals(      2561, rnd.nextInt(i *= 2));
+  Expect.equals(      2548, rnd.nextInt(i *= 2));
+  Expect.equals(      9553, rnd.nextInt(i *= 2));
+  Expect.equals(      2628, rnd.nextInt(i *= 2));
+  Expect.equals(     42376, rnd.nextInt(i *= 2));
+  Expect.equals(    101848, rnd.nextInt(i *= 2));
+  Expect.equals(     85153, rnd.nextInt(i *= 2));
+  Expect.equals(    495595, rnd.nextInt(i *= 2));
+  Expect.equals(    647122, rnd.nextInt(i *= 2));
+  Expect.equals(    793546, rnd.nextInt(i *= 2));
+  Expect.equals(   1073343, rnd.nextInt(i *= 2));
+  Expect.equals(   4479969, rnd.nextInt(i *= 2));
+  Expect.equals(   9680425, rnd.nextInt(i *= 2));
+  Expect.equals(  28460171, rnd.nextInt(i *= 2));
+  Expect.equals(  49481738, rnd.nextInt(i *= 2));
+  Expect.equals(   9878974, rnd.nextInt(i *= 2));
+  Expect.equals( 132552472, rnd.nextInt(i *= 2));
+  Expect.equals( 210267283, rnd.nextInt(i *= 2));
+  Expect.equals( 125422442, rnd.nextInt(i *= 2));
+  Expect.equals( 226275094, rnd.nextInt(i *= 2));
+  Expect.equals(1639629168, rnd.nextInt(i *= 2));
   Expect.equals(0x100000000, i);
   // If max is too large expect an ArgumentError.
   Expect.throws(() => rnd.nextInt(i + 1), (e) => e is ArgumentError);
 
   rnd = new Random(6790);
-  Expect.approxEquals(0.7360144236, rnd.nextDouble());
-  Expect.approxEquals(0.3292339731, rnd.nextDouble());
-  Expect.approxEquals(0.3489622548, rnd.nextDouble());
-  Expect.approxEquals(0.9815975892, rnd.nextDouble());
+  Expect.approxEquals(0.1202733131, rnd.nextDouble());
+  Expect.approxEquals(0.5554054805, rnd.nextDouble());
+  Expect.approxEquals(0.0385160727, rnd.nextDouble());
+  Expect.approxEquals(0.2836345217, rnd.nextDouble());
+}
+
+void checkSeed() {
+  // Check that various seeds generate the expected first values.
+  // 53 significant bits, so the number is representable in JS.
+  var rawSeed = 0x19a32c640e1d71;
+  var expectations = [
+    26007, 43006, 46458, 18610, 16413, 50455,  2164, 47399,  8859,  9732,
+    20367, 33935, 54549, 54913,  4819, 24198, 49353, 22277, 51852, 35959,
+    45347, 12100, 10136, 22372, 15293, 20066,  1351, 49030, 64845, 12793,
+    50916, 55784, 43170, 27653, 34696,  1492, 50255,  9597, 45929,  2874,
+    27629, 53084, 36064, 42140, 32016, 41751, 13967, 20516,   578, 16773,
+    53064, 14814, 22737, 48846, 45147, 10205, 56584, 63711, 44128, 21099,
+    47966, 35471, 39576,  1141, 45716, 54940, 57406, 15437, 31721, 35044,
+    28136, 39797, 50801, 22184, 58686
+  ];
+  var negative_seed_expectations = [
+    12170, 42844, 39228, 64032, 29046, 57572,  8453, 52224, 27060, 28454,
+    20510, 28804, 59221, 53422, 11047, 50864, 33997, 19611,  1250, 65088,
+    19690, 11396,    20, 48867, 44862, 47129, 58724, 13325, 50005, 33320,
+    16523,  4740, 63721, 63272, 30545, 51403, 35845,  3943, 31850, 23148,
+    26307,  1724, 29281, 39988, 43653, 48012, 43810, 16755, 13105, 25325,
+    32648, 19958, 38838,  8322,  3421, 28624, 17269, 45385, 50680,  1696,
+    26088,  2787, 48566, 34357, 27731, 51764,  8455, 16498, 59721, 59568,
+    46333,  7935, 51459, 36766, 50711
+  ];
+  for (var i = 0, m = 1; i < 75; i++) {
+    Expect.equals(expectations[i], new Random(rawSeed * m).nextInt(65536));
+    Expect.equals(negative_seed_expectations[i],
+                  new Random(rawSeed * -m).nextInt(65536));
+    m *= 2;
+  }
+  // And test zero seed too.
+  Expect.equals(21391, new Random(0).nextInt(65536));
 }
diff --git a/tests/lib/mirrors/class_mirror_type_variables_data.dart b/tests/lib/mirrors/class_mirror_type_variables_data.dart
new file mode 100644
index 0000000..e47b96a
--- /dev/null
+++ b/tests/lib/mirrors/class_mirror_type_variables_data.dart
@@ -0,0 +1,19 @@
+// 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.
+
+library class_mirror_type_variables_data;
+
+class NoTypeParams {}
+class A<T, S extends String> {}
+class B<Z extends B<Z>> {}
+class C<Z extends B<Z>> {}
+class D<R,S,T> {
+  R foo(R r) => r;
+  S bar(S s) => s;
+  T baz(T t) => t;
+}
+class Helper<S> {}
+class E<R extends Map<R, Helper<String>>> {}
+class F<Z extends Helper<F<Z>>> {}
+
diff --git a/tests/lib/mirrors/class_mirror_type_variables_expect.dart b/tests/lib/mirrors/class_mirror_type_variables_expect.dart
new file mode 100644
index 0000000..00c5124
--- /dev/null
+++ b/tests/lib/mirrors/class_mirror_type_variables_expect.dart
@@ -0,0 +1,131 @@
+// 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.
+
+// Test expectations for 'class_mirror_type_variables_data.dart'.
+
+library class_mirror_type_variables_expect;
+
+import "dart:mirrors";
+
+import "package:expect/expect.dart";
+
+
+/// The interface of [Env] is shared between the runtime and the source mirrors
+/// test.
+abstract class Env {
+  ClassMirror getA();
+  ClassMirror getB();
+  ClassMirror getC();
+  ClassMirror getD();
+  ClassMirror getE();
+  ClassMirror getF();
+  ClassMirror getNoTypeParams();
+  ClassMirror getObject();
+  ClassMirror getString();
+  ClassMirror getHelperOfString();
+}
+
+void test(Env env) {
+  testNoTypeParams(env);
+  testA(env);
+  testBAndC(env);
+  testD(env);
+  testE(env);
+  testF(env);
+}
+
+testNoTypeParams(Env env) {
+  ClassMirror cm = env.getNoTypeParams();
+  Expect.equals(cm.typeVariables.length, 0);
+}
+
+void testA(Env env) {
+  ClassMirror a = env.getA();
+  Expect.equals(2, a.typeVariables.length);
+
+  TypeVariableMirror aT = a.typeVariables[0];
+  TypeVariableMirror aS = a.typeVariables[1];
+  ClassMirror aTBound = aT.upperBound;
+  ClassMirror aSBound = aS.upperBound;
+
+  Expect.isTrue(aTBound.isOriginalDeclaration);
+  Expect.isTrue(aSBound.isOriginalDeclaration);
+
+  Expect.equals(env.getObject(), aTBound);
+  Expect.equals(env.getString(), aSBound);
+}
+
+void testBAndC(Env env) {
+  ClassMirror b = env.getB();
+  ClassMirror c = env.getC();
+
+  Expect.equals(1, b.typeVariables.length);
+  Expect.equals(1, c.typeVariables.length);
+
+  TypeVariableMirror bZ = b.typeVariables[0];
+  TypeVariableMirror cZ = c.typeVariables[0];
+  ClassMirror bZBound = bZ.upperBound;
+  ClassMirror cZBound = cZ.upperBound;
+
+  Expect.isFalse(bZBound.isOriginalDeclaration);
+  Expect.isFalse(cZBound.isOriginalDeclaration);
+
+  Expect.notEquals(bZBound, cZBound);
+  Expect.equals(b, bZBound.originalDeclaration);
+  Expect.equals(b, cZBound.originalDeclaration);
+
+  TypeMirror bZBoundTypeArgument = bZBound.typeArguments.single;
+  TypeMirror cZBoundTypeArgument = cZBound.typeArguments.single;
+  TypeVariableMirror bZBoundTypeVariable = bZBound.typeVariables.single;
+  TypeVariableMirror cZBoundTypeVariable = cZBound.typeVariables.single;
+
+  Expect.equals(b, bZ.owner);
+  Expect.equals(c, cZ.owner);
+  Expect.equals(b, bZBoundTypeVariable.owner);
+  Expect.equals(b, cZBoundTypeVariable.owner);
+  Expect.equals(b, bZBoundTypeArgument.owner);
+  Expect.equals(c, cZBoundTypeArgument.owner);
+
+  Expect.notEquals(bZ, cZ);
+  Expect.equals(bZ, bZBoundTypeArgument);
+  Expect.equals(cZ, cZBoundTypeArgument);
+  Expect.equals(bZ, bZBoundTypeVariable);
+  Expect.equals(bZ, cZBoundTypeVariable);
+}
+
+testD(Env env) {
+  ClassMirror cm = env.getD();
+  Expect.equals(3, cm.typeVariables.length);
+  var values = cm.typeVariables;
+  values.forEach((e) {
+    Expect.equals(true, e is TypeVariableMirror);
+  });
+  Expect.equals(#R, values.elementAt(0).simpleName);
+  Expect.equals(#S, values.elementAt(1).simpleName);
+  Expect.equals(#T, values.elementAt(2).simpleName);
+}
+
+void testE(Env env) {
+  ClassMirror e = env.getE();
+  TypeVariableMirror eR = e.typeVariables.single;
+  ClassMirror mapRAndHelperOfString = eR.upperBound;
+
+  Expect.isFalse(mapRAndHelperOfString.isOriginalDeclaration);
+  Expect.equals(eR, mapRAndHelperOfString.typeArguments.first);
+  Expect.equals(env.getHelperOfString(),
+      mapRAndHelperOfString.typeArguments.last);
+}
+
+void testF(Env env) {
+  ClassMirror f = env.getF();
+  TypeVariableMirror fZ = f.typeVariables[0];
+  ClassMirror fZBound = fZ.upperBound;
+  ClassMirror fZBoundTypeArgument = fZBound.typeArguments.single;
+
+  Expect.equals(1, f.typeVariables.length);
+  Expect.isFalse(fZBound.isOriginalDeclaration);
+  Expect.isFalse(fZBoundTypeArgument.isOriginalDeclaration);
+  Expect.equals(f, fZBoundTypeArgument.originalDeclaration);
+  Expect.equals(fZ, fZBoundTypeArgument.typeArguments.single);
+}
diff --git a/tests/lib/mirrors/class_mirror_type_variables_test.dart b/tests/lib/mirrors/class_mirror_type_variables_test.dart
index 51da82e..8918de7 100644
--- a/tests/lib/mirrors/class_mirror_type_variables_test.dart
+++ b/tests/lib/mirrors/class_mirror_type_variables_test.dart
@@ -6,120 +6,22 @@
 
 import "package:expect/expect.dart";
 
-class NoTypeParams {}
-class A<T, S extends String> {}
-class B<Z extends B<Z>> {}
-class C<Z extends B<Z>> {}
-class D<R,S,T> {
-  R foo(R r) => r;
-  S bar(S s) => s;
-  T baz(T t) => t;
-}
-class Helper<S> {}
-class E<R extends Map<R, Helper<String>>> {}
-class F<Z extends Helper<F<Z>>> {}
+import "class_mirror_type_variables_data.dart";
+import "class_mirror_type_variables_expect.dart";
 
-testNoTypeParams() {
-  ClassMirror cm = reflectClass(NoTypeParams);
-  Expect.equals(cm.typeVariables.length, 0);
-}
-
-void testA() {
-  ClassMirror a = reflectClass(A);
-  Expect.equals(2, a.typeVariables.length);
-
-  TypeVariableMirror aT = a.typeVariables[0];
-  TypeVariableMirror aS = a.typeVariables[1];
-  ClassMirror aTBound = aT.upperBound;
-  ClassMirror aSBound = aS.upperBound;
-
-  Expect.isTrue(aTBound.isOriginalDeclaration);
-  Expect.isTrue(aSBound.isOriginalDeclaration);
-
-  Expect.equals(reflectClass(Object), aTBound);
-  Expect.equals(reflectClass(String), aSBound);
-}
-
-void testBAndC() {
-  ClassMirror b = reflectClass(B);
-  ClassMirror c = reflectClass(C);
-
-  Expect.equals(1, b.typeVariables.length);
-  Expect.equals(1, c.typeVariables.length);
-
-  TypeVariableMirror bZ = b.typeVariables[0];
-  TypeVariableMirror cZ = c.typeVariables[0];
-  ClassMirror bZBound = bZ.upperBound;
-  ClassMirror cZBound = cZ.upperBound;
-
-  Expect.isFalse(bZBound.isOriginalDeclaration);
-  Expect.isFalse(cZBound.isOriginalDeclaration);
-
-  Expect.notEquals(bZBound, cZBound);
-  Expect.equals(b, bZBound.originalDeclaration);
-  Expect.equals(b, cZBound.originalDeclaration);
-
-  TypeMirror bZBoundTypeArgument = bZBound.typeArguments.single;
-  TypeMirror cZBoundTypeArgument = cZBound.typeArguments.single;
-  TypeVariableMirror bZBoundTypeVariable = bZBound.typeVariables.single;
-  TypeVariableMirror cZBoundTypeVariable = cZBound.typeVariables.single;
-
-  Expect.equals(b, bZ.owner);
-  Expect.equals(c, cZ.owner);
-  Expect.equals(b, bZBoundTypeVariable.owner);
-  Expect.equals(b, cZBoundTypeVariable.owner);
-  Expect.equals(b, bZBoundTypeArgument.owner);
-  Expect.equals(c, cZBoundTypeArgument.owner);
-
-  Expect.notEquals(bZ, cZ);
-  Expect.equals(bZ, bZBoundTypeArgument);
-  Expect.equals(cZ, cZBoundTypeArgument);
-  Expect.equals(bZ, bZBoundTypeVariable);
-  Expect.equals(bZ, cZBoundTypeVariable);
-}
-
-testD() {
-  ClassMirror cm;
-  cm = reflectClass(D);
-  Expect.equals(3, cm.typeVariables.length);
-  var values = cm.typeVariables;
-  values.forEach((e) {
-    Expect.equals(true, e is TypeVariableMirror);
-  });
-  Expect.equals(#R, values.elementAt(0).simpleName);
-  Expect.equals(#S, values.elementAt(1).simpleName);
-  Expect.equals(#T, values.elementAt(2).simpleName);
-}
-
-void testE() {
-  ClassMirror e = reflectClass(E);
-  TypeVariableMirror eR = e.typeVariables.single;
-  ClassMirror mapRAndHelperOfString = eR.upperBound;
-
-  Expect.isFalse(mapRAndHelperOfString.isOriginalDeclaration);
-  Expect.equals(eR, mapRAndHelperOfString.typeArguments.first);
-  Expect.equals(reflect(new Helper<String>()).type,
-      mapRAndHelperOfString.typeArguments.last);
-}
-
-void testF() {
-  ClassMirror f = reflectClass(F);
-  TypeVariableMirror fZ = f.typeVariables[0];
-  ClassMirror fZBound = fZ.upperBound;
-  ClassMirror fZBoundTypeArgument = fZBound.typeArguments.single;
-
-  Expect.equals(1, f.typeVariables.length);
-  Expect.isFalse(fZBound.isOriginalDeclaration);
-  Expect.isFalse(fZBoundTypeArgument.isOriginalDeclaration);
-  Expect.equals(f, fZBoundTypeArgument.originalDeclaration);
-  Expect.equals(fZ, fZBoundTypeArgument.typeArguments.single);
+class RuntimeEnv implements Env {
+  ClassMirror getA() => reflectClass(A);
+  ClassMirror getB() => reflectClass(B);
+  ClassMirror getC() => reflectClass(C);
+  ClassMirror getD() => reflectClass(D);
+  ClassMirror getE() => reflectClass(E);
+  ClassMirror getF() => reflectClass(F);
+  ClassMirror getNoTypeParams() => reflectClass(NoTypeParams);
+  ClassMirror getObject() => reflectClass(Object);
+  ClassMirror getString() => reflectClass(String);
+  ClassMirror getHelperOfString() => reflect(new Helper<String>()).type;
 }
 
 main() {
-  testNoTypeParams();
-  testA();
-  testBAndC();
-  testD();
-  testE();
-  testF();
+  test(new RuntimeEnv());
 }
diff --git a/tests/lib/mirrors/declarations_type_test.dart b/tests/lib/mirrors/declarations_type_test.dart
new file mode 100644
index 0000000..7cdd20e
--- /dev/null
+++ b/tests/lib/mirrors/declarations_type_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2014, 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.
+
+// Regression test for Issue 14972.
+
+library test.declarations_type;
+
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class C {}
+
+main() {
+  var classDeclarations = reflectClass(C).declarations;
+  Expect.isTrue(classDeclarations is Map<Symbol, DeclarationMirror>);
+  Expect.isTrue(classDeclarations.values is Iterable<DeclarationMirror>);
+  Expect.isTrue(classDeclarations.values.where((x) => true) is Iterable<DeclarationMirror>);
+  Expect.isFalse(classDeclarations is Map<Symbol, MethodMirror>);
+  Expect.isFalse(classDeclarations.values is Iterable<MethodMirror>);
+  Expect.isFalse(classDeclarations.values.where((x) => true) is Iterable<MethodMirror>);
+
+  var libraryDeclarations = (reflectClass(C).owner as LibraryMirror).declarations;
+  Expect.isTrue(libraryDeclarations is Map<Symbol, DeclarationMirror>);
+  Expect.isTrue(libraryDeclarations.values is Iterable<DeclarationMirror>);
+  Expect.isTrue(libraryDeclarations.values.where((x) => true) is Iterable<DeclarationMirror>);
+  Expect.isFalse(libraryDeclarations is Map<Symbol, ClassMirror>);
+  Expect.isFalse(libraryDeclarations.values is Iterable<ClassMirror>);
+  Expect.isFalse(libraryDeclarations.values.where((x) => true) is Iterable<ClassMirror>);
+}
diff --git a/tests/lib/mirrors/method_mirror_source_line_ending_cr.dart b/tests/lib/mirrors/method_mirror_source_line_ending_cr.dart
new file mode 100755
index 0000000..851c04c
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_line_ending_cr.dart
Binary files differ
diff --git a/tests/lib/mirrors/method_mirror_source_line_ending_crlf.dart b/tests/lib/mirrors/method_mirror_source_line_ending_crlf.dart
new file mode 100755
index 0000000..bcf3e64
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_line_ending_crlf.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2014, 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.

+

+// This file is marked executable so source control will preserve the type of

+// line ending.

+

+library line_endings.crlf;

+

+oneLineCRLF(x) => x;

+multiLineCRLF(y) {

+  return y + 1;

+}

+c

+(){

+}

diff --git a/tests/lib/mirrors/method_mirror_source_line_ending_lf.dart b/tests/lib/mirrors/method_mirror_source_line_ending_lf.dart
new file mode 100755
index 0000000..71a34c8
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_line_ending_lf.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2014, 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.
+
+// This file is marked executable so source control will preserve the type of
+// line ending.
+
+library line_endings.lf;
+
+oneLineLF(x) => x;
+multiLineLF(y) {
+  return y + 1;
+}
+a
+(){
+}
diff --git a/tests/lib/mirrors/method_mirror_source_line_ending_test.dart b/tests/lib/mirrors/method_mirror_source_line_ending_test.dart
new file mode 100644
index 0000000..e052cc1
--- /dev/null
+++ b/tests/lib/mirrors/method_mirror_source_line_ending_test.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2014, 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.
+
+import "dart:mirrors";
+import "package:expect/expect.dart";
+
+import "method_mirror_source_line_ending_lf.dart";
+import "method_mirror_source_line_ending_cr.dart";
+import "method_mirror_source_line_ending_crlf.dart";
+
+main() {
+  String sourceOf(Function f) => (reflect(f) as ClosureMirror).function.source;
+
+  // Source does not cross line breaks.
+  Expect.stringEquals('oneLineLF(x) => x;', sourceOf(oneLineLF));
+  Expect.stringEquals('oneLineCR(x) => x;', sourceOf(oneLineCR));
+  Expect.stringEquals('oneLineCRLF(x) => x;', sourceOf(oneLineCRLF));
+
+  // Source includes line breaks.
+  Expect.stringEquals('multiLineLF(y) {\n  return y + 1;\n}',
+                      sourceOf(multiLineLF));
+  Expect.stringEquals('multiLineCR(y) {\r  return y + 1;\r}',
+                      sourceOf(multiLineCR));
+  Expect.stringEquals('multiLineCRLF(y) {\r\n  return y + 1;\r\n}',
+                      sourceOf(multiLineCRLF));
+
+  // First and last characters separated from middle by line breaks.
+  Expect.stringEquals('a\n(){\n}', sourceOf(a));
+  Expect.stringEquals('b\r(){\r}', sourceOf(b));
+  Expect.stringEquals('c\r\n(){\r\n}', sourceOf(c));
+}
diff --git a/tests/lib/mirrors/mirrors_reader.dart b/tests/lib/mirrors/mirrors_reader.dart
new file mode 100644
index 0000000..9b16f81
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_reader.dart
@@ -0,0 +1,263 @@
+// Copyright (c) 2014, 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 LICESNE file.
+
+library mirrors.reader;
+
+import 'dart:mirrors';
+import 'mirrors_visitor.dart';
+
+class ReadError {
+  final String tag;
+  final exception;
+  final StackTrace stackTrace;
+
+  ReadError(this.tag, this.exception, this.stackTrace);
+}
+
+class MirrorsReader extends MirrorsVisitor {
+  /// Produce verbose output.
+  final bool verbose;
+  /// Include stack trace in the error report.
+  final bool includeStackTrace;
+
+  bool fatalError = false;
+  Set<Mirror> visited = new Set<Mirror>();
+  Set<TypeMirror> declarations = new Set<TypeMirror>();
+  Set<TypeMirror> instantiations = new Set<TypeMirror>();
+  List<ReadError> errors = <ReadError>[];
+  List<Mirror> queue = <Mirror>[];
+
+  MirrorsReader({this.verbose: false, this.includeStackTrace: false});
+
+  void checkMirrorSystem(MirrorSystem mirrorSystem) {
+    visitMirrorSystem(mirrorSystem);
+    if (!errors.isEmpty) {
+      Set<String> errorMessages = new Set<String>();
+      for (ReadError error in errors) {
+        String text = 'Mirrors read error: ${error.tag}=${error.exception}';
+        if (includeStackTrace) {
+          text = '$text\n${error.stackTrace}';
+        }
+        if (errorMessages.add(text)) {
+          print(text);
+        }
+      }
+      throw 'Unexpected errors occurred reading mirrors.';
+    }
+  }
+
+  // Skip mirrors so that each mirror is only visited once.
+  bool skipMirror(Mirror mirror) {
+    if (fatalError) return true;
+    if (mirror is TypeMirror) {
+      if (mirror.isOriginalDeclaration) {
+        // Visit the declation once.
+        return !declarations.add(mirror);
+      } else {
+        // Visit only one instantiation.
+        return !instantiations.add(mirror.originalDeclaration);
+      }
+    }
+    return !visited.add(mirror);
+  }
+
+  reportError(var receiver, String tag, var exception, StackTrace stackTrace) {
+    String errorTag = '${receiver.runtimeType}.$tag';
+    errors.add(new ReadError(errorTag, exception, stackTrace));
+  }
+
+  visitUnsupported(var receiver, String tag,
+                   UnsupportedError exception,
+                   StackTrace stackTrace) {
+    if (verbose) print('visitUnsupported:$receiver.$tag:$exception');
+    if (!expectUnsupported(receiver, tag, exception) &&
+        !allowUnsupported(receiver, tag, exception)) {
+      reportError(receiver, tag, exception, stackTrace);
+    }
+  }
+
+  /// Override to specify that access is expected to be unsupported.
+  bool expectUnsupported(var receiver, String tag,
+                         UnsupportedError exception) => false;
+
+  /// Override to allow unsupported access.
+  bool allowUnsupported(var receiver, String tag,
+                        UnsupportedError exception) => false;
+
+  /// Evaluates the function [f]. Subclasses can override this to handle
+  /// specific exceptions.
+  evaluate(f()) => f();
+
+  visit(var receiver, String tag, var value) {
+    if (value is Function) {
+      try {
+        var result = evaluate(value);
+        if (expectUnsupported(receiver, tag, null)) {
+          reportError(receiver, tag, 'Expected UnsupportedError.', null);
+        }
+        return visit(receiver, tag, result);
+      } on UnsupportedError catch (e, s) {
+        visitUnsupported(receiver, tag, e, s);
+      } on OutOfMemoryError catch (e, s) {
+        reportError(receiver, tag, e, s);
+        fatalError = true;
+      } on StackOverflowError catch (e, s) {
+        reportError(receiver, tag, e, s);
+        fatalError = true;
+      } catch (e, s) {
+        reportError(receiver, tag, e, s);
+      }
+    } else {
+      if (value is Mirror) {
+        if (!skipMirror(value)) {
+          if (verbose) print('visit:$receiver.$tag=$value');
+          bool drain = queue.isEmpty;
+          queue.add(value);
+          if (drain) {
+            while (!queue.isEmpty) {
+              visitMirror(queue.removeLast());
+            }
+          }
+        }
+      } else if (value is MirrorSystem) {
+        visitMirrorSystem(value);
+      } else if (value is SourceLocation) {
+        visitSourceLocation(value);
+      } else if (value is Iterable) {
+        // TODO(johnniwinther): Merge with `immutable_collections_test.dart`.
+        value.forEach((e) {
+          visit(receiver, tag, e);
+        });
+      } else if (value is Map) {
+        value.forEach((k, v) {
+          visit(receiver, tag, k);
+          visit(receiver, tag, v);
+        });
+      }
+    }
+    return value;
+  }
+
+  visitMirrorSystem(MirrorSystem mirrorSystem) {
+    visit(mirrorSystem, 'dynamicType', () => mirrorSystem.dynamicType);
+    visit(mirrorSystem, 'voidType', () => mirrorSystem.voidType);
+    visit(mirrorSystem, 'libraries', () => mirrorSystem.libraries);
+  }
+
+  visitClassMirror(ClassMirror mirror) {
+    super.visitClassMirror(mirror);
+    visit(mirror, 'declarations', () => mirror.declarations);
+    bool hasReflectedType =
+        visit(mirror, 'hasReflectedType', () => mirror.hasReflectedType);
+    visit(mirror, 'instanceMembers', () => mirror.instanceMembers);
+    visit(mirror, 'mixin', () => mirror.mixin);
+    if (hasReflectedType) {
+      visit(mirror, 'reflectedType', () => mirror.reflectedType);
+    }
+    visit(mirror, 'staticMembers', () => mirror.staticMembers);
+    visit(mirror, 'superclass', () => mirror.superclass);
+    visit(mirror, 'superinterfaces', () => mirror.superinterfaces);
+  }
+
+  visitDeclarationMirror(DeclarationMirror mirror) {
+    super.visitDeclarationMirror(mirror);
+    visit(mirror, 'isPrivate', () => mirror.isPrivate);
+    visit(mirror, 'isTopLevel', () => mirror.isTopLevel);
+    visit(mirror, 'location', () => mirror.location);
+    visit(mirror, 'metadata', () => mirror.metadata);
+    visit(mirror, 'owner', () => mirror.owner);
+    visit(mirror, 'qualifiedName', () => mirror.qualifiedName);
+    visit(mirror, 'simpleName', () => mirror.simpleName);
+  }
+
+  visitFunctionTypeMirror(FunctionTypeMirror mirror) {
+    super.visitFunctionTypeMirror(mirror);
+    visit(mirror, 'callMethod', () => mirror.callMethod);
+    visit(mirror, 'parameters', () => mirror.parameters);
+    visit(mirror, 'returnType', () => mirror.returnType);
+  }
+
+  visitInstanceMirror(InstanceMirror mirror) {
+    super.visitInstanceMirror(mirror);
+    bool hasReflectee =
+        visit(mirror, 'hasReflectee', () => mirror.hasReflectee);
+    if (hasReflectee) {
+      visit(mirror, 'reflectee', () => mirror.reflectee);
+    }
+    visit(mirror, 'type', () => mirror.type);
+  }
+
+  visitLibraryMirror(LibraryMirror mirror) {
+    super.visitLibraryMirror(mirror);
+    visit(mirror, 'declarations', () => mirror.declarations);
+    visit(mirror, 'topLevelMembers', () => mirror.topLevelMembers);
+    visit(mirror, 'uri', () => mirror.uri);
+  }
+
+  visitMethodMirror(MethodMirror mirror) {
+    super.visitMethodMirror(mirror);
+    visit(mirror, 'constructorName', () => mirror.constructorName);
+    visit(mirror, 'isAbstract', () => mirror.isAbstract);
+    visit(mirror, 'isConstConstructor', () => mirror.isConstConstructor);
+    visit(mirror, 'isConstructor', () => mirror.isConstructor);
+    visit(mirror, 'isFactoryConstructor',
+          () => mirror.isFactoryConstructor);
+    visit(mirror, 'isGenerativeConstructor',
+          () => mirror.isGenerativeConstructor);
+    visit(mirror, 'isGetter', () => mirror.isGetter);
+    visit(mirror, 'isOperator', () => mirror.isOperator);
+    visit(mirror, 'isRedirectingConstructor',
+          () => mirror.isRedirectingConstructor);
+    visit(mirror, 'isRegularMethod', () => mirror.isRegularMethod);
+    visit(mirror, 'isSetter', () => mirror.isSetter);
+    visit(mirror, 'isStatic', () => mirror.isStatic);
+    visit(mirror, 'isSynthetic', () => mirror.isSynthetic);
+    visit(mirror, 'parameters', () => mirror.parameters);
+    visit(mirror, 'returnType', () => mirror.returnType);
+    visit(mirror, 'source', () => mirror.source);
+  }
+
+  visitParameterMirror(ParameterMirror mirror) {
+    super.visitParameterMirror(mirror);
+    bool hasDefaultValue =
+        visit(mirror, 'hasDefaultValue', () => mirror.hasDefaultValue);
+    if (hasDefaultValue) {
+      visit(mirror, 'defaultValue', () => mirror.defaultValue);
+    }
+    visit(mirror, 'isNamed', () => mirror.isNamed);
+    visit(mirror, 'isOptional', () => mirror.isOptional);
+    visit(mirror, 'type', () => mirror.type);
+  }
+
+  visitSourceLocation(SourceLocation location) {
+
+  }
+
+  visitTypedefMirror(TypedefMirror mirror) {
+    super.visitTypedefMirror(mirror);
+    visit(mirror, 'referent', () => mirror.referent);
+  }
+
+  visitTypeMirror(TypeMirror mirror) {
+    super.visitTypeMirror(mirror);
+    visit(mirror, 'isOriginalDeclaration',
+          () => mirror.isOriginalDeclaration);
+    visit(mirror, 'originalDeclaration', () => mirror.originalDeclaration);
+    visit(mirror, 'typeArguments', () => mirror.typeArguments);
+    visit(mirror, 'typeVariables', () => mirror.typeVariables);
+  }
+
+  visitTypeVariableMirror(TypeVariableMirror mirror) {
+    super.visitTypeVariableMirror(mirror);
+    visit(mirror, 'upperBound', () => mirror.upperBound);
+  }
+
+  visitVariableMirror(VariableMirror mirror) {
+    super.visitVariableMirror(mirror);
+    visit(mirror, 'isConst', () => mirror.isConst);
+    visit(mirror, 'isFinal', () => mirror.isFinal);
+    visit(mirror, 'isStatic', () => mirror.isStatic);
+    visit(mirror, 'type', () => mirror.type);
+  }
+}
\ No newline at end of file
diff --git a/tests/lib/mirrors/mirrors_reader_test.dart b/tests/lib/mirrors/mirrors_reader_test.dart
new file mode 100644
index 0000000..4cd7b8c
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_reader_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2014, 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.
+
+// Test that everything reachable from a [MirrorSystem] can be accessed.
+
+library test.mirrors.reader;
+
+import 'dart:mirrors';
+import 'mirrors_reader.dart';
+
+class RuntimeMirrorsReader extends MirrorsReader {
+  final String mirrorSystemType;
+
+  RuntimeMirrorsReader(MirrorSystem mirrorSystem,
+                      {bool verbose: false, bool includeStackTrace: false})
+      : this.mirrorSystemType = '${mirrorSystem.runtimeType}',
+        super(verbose: verbose, includeStackTrace: includeStackTrace);
+
+  bool allowUnsupported(var receiver, String tag, UnsupportedError exception) {
+    if (mirrorSystemType == '_LocalMirrorSystem') {
+      // VM mirror system.
+    } else if (mirrorSystemType == 'JsMirrorSystem') {
+      // Dart2js runtime mirror system.
+      if (tag.endsWith('.metadata')) {
+        return true;// Issue 10905.
+      }
+    }
+    return false;
+  }
+
+  bool expectUnsupported(var receiver, String tag, UnsupportedError exception) {
+    // [DeclarationMirror.location] is intentionally not supported in runtime
+    // mirrors.
+    if (receiver is DeclarationMirror && tag == 'location') {
+      return true;
+    }
+    if (mirrorSystemType == '_LocalMirrorSystem') {
+      // VM mirror system.
+    } else if (mirrorSystemType == 'JsMirrorSystem') {
+      // Dart2js runtime mirror system.
+    }
+    return false;
+  }
+}
+
+void main([List<String> arguments = const <String>[]]) {
+  MirrorSystem mirrors = currentMirrorSystem();
+  MirrorsReader reader = new RuntimeMirrorsReader(mirrors,
+      verbose: arguments.contains('-v'),
+      includeStackTrace: arguments.contains('-s'));
+  reader.checkMirrorSystem(mirrors);
+}
diff --git a/tests/lib/mirrors/mirrors_visitor.dart b/tests/lib/mirrors/mirrors_visitor.dart
new file mode 100644
index 0000000..3eef8ee
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_visitor.dart
@@ -0,0 +1,92 @@
+// Copyright (c) 2014, 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.
+
+library mirrors.visitor;
+
+import 'dart:mirrors';
+
+abstract class MirrorsVisitor {
+  visitMirror(Mirror mirror) {
+    if (mirror == null) return;
+
+    if (mirror is FunctionTypeMirror) {
+      visitFunctionTypeMirror(mirror);
+    } else if (mirror is ClassMirror) {
+      visitClassMirror(mirror);
+    } else if (mirror is TypedefMirror) {
+      visitTypedefMirror(mirror);
+    } else if (mirror is TypeVariableMirror) {
+      visitTypeVariableMirror(mirror);
+    } else if (mirror is TypeMirror) {
+      visitTypeMirror(mirror);
+    } else if (mirror is ParameterMirror) {
+      visitParameterMirror(mirror);
+    } else if (mirror is VariableMirror) {
+      visitVariableMirror(mirror);
+    } else if (mirror is MethodMirror) {
+      visitMethodMirror(mirror);
+    } else if (mirror is LibraryMirror) {
+      visitLibraryMirror(mirror);
+    } else if (mirror is InstanceMirror) {
+      visitInstanceMirror(mirror);
+    } else if (mirror is ObjectMirror) {
+      visitObjectMirror(mirror);
+    } else if (mirror is DeclarationMirror) {
+      visitDeclarationMirror(mirror);
+    } else {
+      throw new StateError(
+          'Unexpected mirror kind ${mirror.runtimeType}: $mirror');
+    }
+  }
+
+  visitClassMirror(ClassMirror mirror) {
+    visitObjectMirror(mirror);
+    visitTypeMirror(mirror);
+  }
+
+  visitDeclarationMirror(DeclarationMirror mirror) {
+
+  }
+
+  visitFunctionTypeMirror(FunctionTypeMirror mirror) {
+    visitClassMirror(mirror);
+  }
+
+  visitInstanceMirror(InstanceMirror mirror) {
+    visitObjectMirror(mirror);
+  }
+
+  visitLibraryMirror(LibraryMirror mirror) {
+    visitObjectMirror(mirror);
+    visitDeclarationMirror(mirror);
+  }
+
+  visitMethodMirror(MethodMirror mirror) {
+    visitDeclarationMirror(mirror);
+  }
+
+  visitObjectMirror(ObjectMirror mirror) {
+
+  }
+
+  visitParameterMirror(ParameterMirror mirror) {
+    visitVariableMirror(mirror);
+  }
+
+  visitTypedefMirror(TypedefMirror mirror) {
+    visitTypeMirror(mirror);
+  }
+
+  visitTypeMirror(TypeMirror mirror) {
+    visitDeclarationMirror(mirror);
+  }
+
+  visitTypeVariableMirror(TypeVariableMirror mirror) {
+    visitTypeMirror(mirror);
+  }
+
+  visitVariableMirror(VariableMirror mirror) {
+    visitDeclarationMirror(mirror);
+  }
+}
\ No newline at end of file
diff --git a/tests/lib/typed_data/float64x2_functional_test.dart b/tests/lib/typed_data/float64x2_functional_test.dart
new file mode 100644
index 0000000..642b42b
--- /dev/null
+++ b/tests/lib/typed_data/float64x2_functional_test.dart
@@ -0,0 +1,295 @@
+// 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.
+// VMOptions=--deoptimization_counter_threshold=1000 --optimization-counter-threshold=10
+
+// Library tag to be able to run in html test framework.
+library float32x4_test;
+
+import "package:expect/expect.dart";
+import 'dart:typed_data';
+
+testConstructor() {
+  var a = new Float64x2(1.0, 2.0);
+  Expect.equals(1.0, a.x);
+  Expect.equals(2.0, a.y);
+  var b = new Float64x2.splat(1.0);
+  Expect.equals(1.0, b.x);
+  Expect.equals(1.0, b.y);
+  var c = new Float64x2.zero();
+  Expect.equals(0.0, c.x);
+  Expect.equals(0.0, c.y);
+}
+
+testCastConstructor() {
+  var a = new Float32x4(9.0, 8.0, 7.0, 6.0);
+  var b = new Float64x2.fromFloat32x4(a);
+  Expect.equals(9.0, b.x);
+  Expect.equals(8.0, b.y);
+  var c = new Float32x4.fromFloat64x2(b);
+  Expect.equals(9.0, c.x);
+  Expect.equals(8.0, c.y);
+  Expect.equals(0.0, c.z);
+  Expect.equals(0.0, c.w);
+}
+
+testLaneSetter() {
+  var a = new Float64x2.zero();
+  Expect.equals(0.0, a.x);
+  Expect.equals(0.0, a.y);
+  var b = a.withX(99.0);
+  Expect.equals(0.0, a.x);
+  Expect.equals(0.0, a.y);
+  Expect.equals(99.0, b.x);
+  Expect.equals(0.0, b.y);
+  var c = a.withY(88.0);
+  Expect.equals(0.0, a.x);
+  Expect.equals(0.0, a.y);
+  Expect.equals(0.0, c.x);
+  Expect.equals(88.0, c.y);
+  var d = c.withX(11.0);
+  Expect.equals(0.0, c.x);
+  Expect.equals(88.0, c.y);
+  Expect.equals(11.0, d.x);
+  Expect.equals(88.0, d.y);
+}
+
+testNegate() {
+  var m = new Float64x2(1.0, -2.0);
+  var o = -m;
+  Expect.equals(-1.0, o.x);
+  Expect.equals(2.0, o.y);
+}
+
+testAdd() {
+  var m = new Float64x2(1.0, -2.0);
+  var n = new Float64x2(1.0, 2.0);
+  var o = m + n;
+  Expect.equals(2.0, o.x);
+  Expect.equals(0.0, o.y);
+}
+
+testSub() {
+  var m = new Float64x2(1.0, -2.0);
+  var n = new Float64x2(1.0, 2.0);
+  var o = m - n;
+  Expect.equals(0.0, o.x);
+  Expect.equals(-4.0, o.y);
+}
+
+testMul() {
+  var m = new Float64x2(1.0, -2.0);
+  var n = new Float64x2(2.0, 2.0);
+  var o = m * n;
+  Expect.equals(2.0, o.x);
+  Expect.equals(-4.0, o.y);
+}
+
+testDiv() {
+  var m = new Float64x2(1.0, -2.0);
+  var n = new Float64x2(2.0, 2.0);
+  var o = m / n;
+  Expect.equals(0.5, o.x);
+  Expect.equals(-1.0, o.y);
+}
+
+testScale() {
+  var m = new Float64x2(1.0, 0.5);
+  var n = m.scale(2.0);
+  Expect.equals(2.0, n.x);
+  Expect.equals(1.0, n.y);
+}
+
+testAbs() {
+  var m = new Float64x2(1.0, -0.5).abs();
+  var n = new Float64x2(-2.0, 1.0).abs();
+  Expect.equals(1.0, m.x);
+  Expect.equals(0.5, m.y);
+  Expect.equals(2.0, n.x);
+  Expect.equals(1.0, n.y);
+}
+
+testClamp() {
+  var m = new Float64x2(1.0, -2.0);
+  var lo = new Float64x2(0.0, 0.0);
+  var hi = new Float64x2(2.0, 2.0);
+  m = m.clamp(lo, hi);
+  Expect.equals(1.0, m.x);
+  Expect.equals(0.0, m.y);
+}
+
+testSignMask() {
+  var m = new Float64x2(-1.0, -0.0);
+  Expect.equals(3, m.signMask);
+  m = new Float64x2(0.0, 0.0);
+  Expect.equals(0, m.signMask);
+  m = new Float64x2(-1.0, 0.0);
+  Expect.equals(1, m.signMask);
+  m = new Float64x2(1.0, -0.0);
+  Expect.equals(2, m.signMask);
+}
+
+testMin() {
+  var m = new Float64x2(0.0, -99.0);
+  var n = new Float64x2(-1.0, -1.0);
+  var o = m.min(n);
+  Expect.equals(-1.0, o.x);
+  Expect.equals(-99.0, o.y);
+}
+
+testMax() {
+  var m = new Float64x2(0.0, -99.0);
+  var n = new Float64x2(-1.0, -1.0);
+  var o = m.max(n);
+  Expect.equals(0.0, o.x);
+  Expect.equals(-1.0, o.y);
+}
+
+testSqrt() {
+  var m = new Float64x2(9.0, 16.0);
+  var o = m.sqrt();
+  Expect.equals(3.0, o.x);
+  Expect.equals(4.0, o.y);
+}
+
+testTypedList() {
+  var m = new Float64x2List(2);
+  var n = m[0];
+  Expect.equals(0.0, n.x);
+  Expect.equals(0.0, n.y);
+  n = n.withX(1.0);
+  n = n.withY(2.0);
+  m[0] = n;
+  n = n.withX(99.0);
+  Expect.equals(99.0, n.x);
+  Expect.equals(1.0, m[0].x);
+  Expect.equals(2.0, m[0].y);
+}
+
+testTypedListFromList() {
+  var l = [new Float64x2(1.0, 2.0), new Float64x2(3.0, 4.0)];
+  var m = new Float64x2List.fromList(l);
+  Expect.equals(2, m.length);
+  Expect.equals(16, m.elementSizeInBytes);
+  Expect.equals(32, m.lengthInBytes);
+  Expect.equals(1.0, m[0].x);
+  Expect.equals(2.0, m[0].y);
+  Expect.equals(3.0, m[1].x);
+  Expect.equals(4.0, m[1].y);
+}
+
+testTypedListFromTypedList() {
+  var l = new Float64x2List(2);
+  l[0] = new Float64x2(1.0, 2.0);
+  l[1] = new Float64x2(3.0, 4.0);
+  Expect.equals(2, l.length);
+  Expect.equals(16, l.elementSizeInBytes);
+  Expect.equals(32, l.lengthInBytes);
+  Expect.equals(1.0, l[0].x);
+  Expect.equals(2.0, l[0].y);
+  Expect.equals(3.0, l[1].x);
+  Expect.equals(4.0, l[1].y);
+  var m = new Float64x2List.fromList(l);
+  Expect.equals(2, m.length);
+  Expect.equals(16, m.elementSizeInBytes);
+  Expect.equals(32, m.lengthInBytes);
+  Expect.equals(2, m.length);
+  Expect.equals(1.0, m[0].x);
+  Expect.equals(2.0, m[0].y);
+  Expect.equals(3.0, m[1].x);
+  Expect.equals(4.0, m[1].y);
+}
+
+testTypedListView() {
+  var l = [1.0, 2.0, 3.0, 4.0];
+  Expect.equals(4, l.length);
+  l = new Float64List.fromList(l);
+  Expect.equals(4, l.length);
+  var m = new Float64x2List.view(l.buffer);
+  Expect.equals(2, m.length);
+  Expect.equals(1.0, m[0].x);
+  Expect.equals(2.0, m[0].y);
+  Expect.equals(3.0, m[1].x);
+  Expect.equals(4.0, m[1].y);
+}
+
+testTypedListFullView() {
+  var l = [new Float64x2(1.0, 2.0), new Float64x2(3.0, 4.0)];
+  var m = new Float64x2List.fromList(l);
+  Expect.equals(2, m.length);
+  Expect.equals(1.0, m[0].x);
+  Expect.equals(2.0, m[0].y);
+  Expect.equals(3.0, m[1].x);
+  Expect.equals(4.0, m[1].y);
+  // Create a view which spans the entire buffer.
+  var n = new Float64x2List.view(m.buffer);
+  Expect.equals(2, n.length);
+  Expect.equals(1.0, n[0].x);
+  Expect.equals(2.0, n[0].y);
+  Expect.equals(3.0, n[1].x);
+  Expect.equals(4.0, n[1].y);
+  // Create a view which spans the entire buffer by specifying length.
+  var o = new Float64x2List.view(m.buffer, 0, 2);
+  Expect.equals(2, o.length);
+  Expect.equals(1.0, o[0].x);
+  Expect.equals(2.0, o[0].y);
+  Expect.equals(3.0, o[1].x);
+  Expect.equals(4.0, o[1].y);
+}
+
+testSubList() {
+  var l = [new Float64x2(1.0, 2.0), new Float64x2(3.0, 4.0)];
+  var m = new Float64x2List.fromList(l);
+  var n = m.sublist(0, 1);
+  Expect.equals(1, n.length);
+  Expect.equals(1.0, n[0].x);
+  Expect.equals(2.0, n[0].y);
+  var o = m.sublist(1, 2);
+  Expect.equals(1, o.length);
+  Expect.equals(3.0, o[0].x);
+  Expect.equals(4.0, o[0].y);
+}
+
+testSubView() {
+  var l = [new Float64x2(1.0, 2.0), new Float64x2(3.0, 4.0)];
+  var m = new Float64x2List.fromList(l);
+  var n = new Float64x2List.view(m.buffer, 16, 1);
+  Expect.equals(1, n.length);
+  Expect.equals(16, n.offsetInBytes);
+  Expect.equals(16, n.lengthInBytes);
+  Expect.equals(3.0, n[0].x);
+  Expect.equals(4.0, n[0].y);
+  var o = new Float64x2List.view(m.buffer, 0, 1);
+  Expect.equals(1, o.length);
+  Expect.equals(0, o.offsetInBytes);
+  Expect.equals(16, o.lengthInBytes);
+  Expect.equals(1.0, o[0].x);
+  Expect.equals(2.0, o[0].y);
+}
+
+main() {
+  for (int i = 0; i < 20; i++) {
+    testConstructor();
+    testCastConstructor();
+    testLaneSetter();
+    testNegate();
+    testAdd();
+    testSub();
+    testMul();
+    testDiv();
+    testScale();
+    testAbs();
+    testClamp();
+    testSignMask();
+    testMin();
+    testMax();
+    testSqrt();
+    testTypedList();
+    testTypedListFromList();
+    testTypedListFromTypedList();
+    testTypedListView();
+    testTypedListFullView();
+    testSubList();
+    testSubView();
+  }
+}
diff --git a/tests/lib/typed_data/typed_data_load2_test.dart b/tests/lib/typed_data/typed_data_load2_test.dart
new file mode 100644
index 0000000..3775615
--- /dev/null
+++ b/tests/lib/typed_data/typed_data_load2_test.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2014, 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.
+
+// Test that the compiler's load elimination phase sees interfering writes to
+// the array's buffer.
+
+import "dart:typed_data";
+import 'package:expect/expect.dart';
+
+aliasWithByteData1() {
+  var aa = new Int8List(10);
+  var b = new ByteData.view(aa.buffer);
+  for (int i = 0; i < aa.length; i++) aa[i] = 9;
+
+  var x1 = aa[3];
+  b.setInt8(3, 1);
+  var x2 = aa[3];
+
+  Expect.equals(9, x1);
+  Expect.equals(1, x2);
+}
+
+aliasWithByteData2() {
+  var b = new ByteData(10);
+  var aa = new Int8List.view(b.buffer);
+  for (int i = 0; i < aa.length; i++) aa[i] = 9;
+
+  var x1 = aa[3];
+  b.setInt8(3, 1);
+  var x2 = aa[3];
+
+  Expect.equals(9, x1);
+  Expect.equals(1, x2);
+}
+
+alias8x8() {
+  var buffer = new Int8List(10).buffer;
+  var a1 = new Int8List.view(buffer);
+  var a2 = new Int8List.view(buffer, 1);
+
+  for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+  // Different indexes that alias.
+  var x1 = a1[1];
+  a2[0] = 0;
+  var x2 = a1[1];
+  Expect.equals(9, x1);
+  Expect.equals(0, x2);
+
+  for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+  // Same indexes that don't alias.
+  x1 = a1[1];
+  a2[1] = 5;
+  x2 = a1[1];
+  Expect.equals(9, x1);
+  Expect.equals(9, x2);
+}
+
+alias8x16() {
+  var a1 = new Int8List(10);
+  var a2 = new Int16List.view(a1.buffer);
+
+  for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+  // Same indexes that alias.
+  var x1 = a1[0];
+  a2[0] = 0x101;
+  var x2 = a1[0];
+  Expect.equals(9, x1);
+  Expect.equals(1, x2);
+
+  for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+  // Different indexes that alias.
+  x1 = a1[4];
+  a2[2] = 0x505;
+  x2 = a1[4];
+  Expect.equals(9, x1);
+  Expect.equals(5, x2);
+
+  for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+  // Same indexes that don't alias.
+  x1 = a1[3];
+  a2[3] = 0x505;
+  x2 = a1[3];
+  Expect.equals(9, x1);
+  Expect.equals(9, x2);
+
+  for (int i = 0; i < a1.length; i++) a1[i] = 9;
+
+  // Different indexes don't alias.
+  x1 = a1[2];
+  a2[0] = 0x505;
+  x2 = a1[2];
+  Expect.equals(9, x1);
+  Expect.equals(9, x2);
+}
+
+main() {
+  aliasWithByteData1();
+  aliasWithByteData2();
+  alias8x8();
+  alias8x16();
+}
diff --git a/tests/standalone/io/file_stat_test.dart b/tests/standalone/io/file_stat_test.dart
index 28fbcc3..429d337 100644
--- a/tests/standalone/io/file_stat_test.dart
+++ b/tests/standalone/io/file_stat_test.dart
@@ -14,8 +14,10 @@
 void testStat() {
   Directory directory = Directory.systemTemp.createTempSync('dart_file_stat');
   File file = new File(join(directory.path, "file"));
-  Expect.throws(file.statSync);
-  Expect.throws(() => FileStat.statSync(file.path));
+  FileStat fileStat = FileStat.statSync(file.path);
+  FileStat fileStatDirect = file.statSync();
+  Expect.equals(FileSystemEntityType.NOT_FOUND, fileStat.type);
+  Expect.equals(FileSystemEntityType.NOT_FOUND, fileStatDirect.type);
   file.writeAsStringSync("Dart IO library test of FileStat");
   new Timer(const Duration(seconds: 2), () {
     file.readAsStringSync();
@@ -52,11 +54,11 @@
   .then((directory) {
     File file = new File(join(directory.path, "file"));
     return FileStat.stat(file.path)
-    .then((_) => Expect.fail("FileStat.stat should throw an exception."))
-    .catchError((e) => null)
+    .then((fileStat) => Expect.equals(FileSystemEntityType.NOT_FOUND,
+                                      fileStat.type))
     .then((_) => file.stat())
-    .then((_) => Expect.fail("File.stat should throw an exception."))
-    .catchError((e) => null)
+    .then((fileStat) => Expect.equals(FileSystemEntityType.NOT_FOUND,
+                                      fileStat.type))
     .then((_) => file.writeAsString("Dart IO library test of FileStat"))
     .then((_) => new Future.delayed(const Duration(seconds: 2)))
     .then((_) => file.readAsString())
diff --git a/tests/standalone/io/file_windows_test.dart b/tests/standalone/io/file_windows_test.dart
new file mode 100644
index 0000000..f27f49f
--- /dev/null
+++ b/tests/standalone/io/file_windows_test.dart
@@ -0,0 +1,29 @@
+// 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.
+
+import 'dart:io';
+
+import "package:expect/expect.dart";
+
+void testDeleteLongPathPrefix() {
+  var dir = Directory.systemTemp.createTempSync('dart_file_win');
+  var dirPath = "\\\\?\\${dir.path}";
+  var subPath = dirPath;
+  for (int i = 0; i < 16; i++) {
+    subPath += "\\a-long-path-segment";
+    dir = new Directory(subPath)..createSync();
+  }
+  Expect.isTrue(dir.path.length > 256);
+  var prefixDir = new Directory(dirPath);
+  Expect.isTrue(prefixDir.existsSync());
+  prefixDir.deleteSync(recursive: true);
+  Expect.isFalse(dir.existsSync());
+  Expect.isFalse(prefixDir.existsSync());
+}
+
+
+void main() {
+  if (!Platform.isWindows) return;
+  testDeleteLongPathPrefix();
+}
diff --git a/tests/standalone/io/http_headers_test.dart b/tests/standalone/io/http_headers_test.dart
index d1d261f..7417d56 100644
--- a/tests/standalone/io/http_headers_test.dart
+++ b/tests/standalone/io/http_headers_test.dart
@@ -436,6 +436,13 @@
   Expect.throws(() => new _Cookie.fromSetCookieValue("xxx"));
   Expect.throws(() => new _Cookie.fromSetCookieValue(
       "xxx=yyy; expires=12 jan 2013"));
+
+  _HttpHeaders headers = new _HttpHeaders("1.1");
+  headers.set('Cookie',
+              'DARTSESSID=d3d6fdd78d51aaaf2924c32e991f4349; undefined');
+  Expect.equals('DARTSESSID', headers._parseCookies().single.name);
+  Expect.equals('d3d6fdd78d51aaaf2924c32e991f4349',
+                headers._parseCookies().single.value);
 }
 
 void testHeaderLists() {
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 6cc81d2..fc3c77b 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -9,7 +9,7 @@
 
 package/invalid_uri_test: Fail, OK # CompileTimeErrors intentionally
 
-issue14236_test: Crash # Issue 14516.
+issue14236_test: Crash, RuntimeError # Issue 14516.
 
 [ $runtime == vm ]
 package/package_isolate_test: Fail # Issue 12474
diff --git a/tests/utils/source_mirrors_test.dart b/tests/utils/source_mirrors_test.dart
new file mode 100644
index 0000000..f587560
--- /dev/null
+++ b/tests/utils/source_mirrors_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2012, 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.
+// VMOptions=
+// VMOptions=--print-object-histogram
+
+// Smoke test of the dart2js compiler API.
+library source_mirrors_test;
+
+import 'dart:async';
+import "package:async_helper/async_helper.dart";
+
+import '../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart';
+import 'dummy_compiler_test.dart';
+
+main() {
+  asyncStart();
+  Future result =
+      analyze([new Uri(scheme: 'main')],
+              new Uri(scheme: 'lib', path: '/'),
+              new Uri(scheme: 'package', path: '/'),
+              provider, handler);
+  result.then((mirrorSystem) {
+    if (mirrorSystem == null) {
+      throw 'Analysis failed';
+    }
+    mirrorSystem.libraries.forEach((uri, library) {
+      print(library);
+      library.declarations.forEach((name, declaration) {
+        print(' $name:$declaration');
+      });
+    });
+  }, onError: (e) {
+      throw 'Analysis failed';
+  }).then(asyncSuccess);
+}
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index be55dba..1d71869 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -16,3 +16,8 @@
 [ $compiler == none && $runtime == dartium ]
 dart2js_test: Skip # Uses dart:io.
 
+[ $compiler == dartanalyzer ]
+source_mirrors_test: StaticWarning # issue 16466
+
+[ $compiler == dart2analyzer ]
+source_mirrors_test: StaticWarning # issue 16466
diff --git a/tools/VERSION b/tools/VERSION
index 6f3dbda..624a175 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 1
 MINOR 2
 PATCH 0
-PRERELEASE 3
-PRERELEASE_PATCH 2
+PRERELEASE 4
+PRERELEASE_PATCH 0
diff --git a/tools/bots/bot.py b/tools/bots/bot.py
index ad0ad00..bf99227 100644
--- a/tools/bots/bot.py
+++ b/tools/bots/bot.py
@@ -151,7 +151,8 @@
 
   try:
     Clobber()
-    build_step(build_info)
+    if build_step: 
+      build_step(build_info)
 
     custom_steps(build_info)
   except OSError as e:
diff --git a/tools/bots/pub.py b/tools/bots/pub.py
index 73db559..dddb655 100755
--- a/tools/bots/pub.py
+++ b/tools/bots/pub.py
@@ -48,7 +48,7 @@
     common_args.append('--builder-tag=%s' % build_info.builder_tag)
                  
   bot.RunTest('pub', build_info,
-              common_args + ['pub', 'pkg', 'dartdoc', 'docs'])
+              common_args + ['pub', 'pkg', 'docs'])
 
   pkgbuild_build_info = bot.BuildInfo('none', 'vm', 'release',
       build_info.system, checked=False)
diff --git a/tools/bots/src-tarball.py b/tools/bots/src-tarball.py
new file mode 100644
index 0000000..3441e93
--- /dev/null
+++ b/tools/bots/src-tarball.py
@@ -0,0 +1,42 @@
+#!/usr/bin/python
+
+# Copyright (c) 2014, 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.
+
+"""
+Buildbot steps for src tarball generation and debian package generation
+
+Package up the src of the dart repo and create a debian package.
+Archive tarball and debian package to google cloud storage.
+"""
+
+import re
+import sys
+
+import bot
+
+SRC_BUILDER = r'src-tarball-linux'
+
+def SrcConfig(name, is_buildbot):
+  """Returns info for the current buildbot based on the name of the builder.
+
+  Currently, since we only run this on linux, this is just:
+  - mode: always "release"
+  - system: always "linux"
+  """
+  src_pattern = re.match(SRC_BUILDER, name)
+  if not src_pattern:
+    return None
+
+  return bot.BuildInfo('none', 'none', 'release', 'linux')
+
+def SrcSteps(build_info):
+  with bot.BuildStep('Create src tarball'):
+    args = [sys.executable, './tools/create_tarball.py']
+    print 'Building src tarball'
+    bot.RunProcess(args)
+
+if __name__ == '__main__':
+  # We pass in None for build_step to avoid building the sdk.
+  bot.RunBot(SrcConfig, SrcSteps, build_step=None)
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 2fe0851..4d12ae8 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -105,7 +105,7 @@
 
 
 def CopyDartScripts(home, sdk_root):
-  for executable in ['dart2js', 'dartanalyzer', 'dartdoc', 'docgen', 'pub']:
+  for executable in ['dart2js', 'dartanalyzer', 'docgen', 'pub']:
     CopyShellScript(os.path.join(home, 'sdk', 'bin', executable),
                     os.path.join(sdk_root, 'bin'))
 
@@ -194,7 +194,6 @@
 
   for library in [join('_chrome', 'dart2js'), join('_chrome', 'dartium'),
                   join('_internal', 'compiler'),
-                  join('_internal', 'dartdoc'),
                   join('_internal', 'lib'),
                   'async', 'collection', 'convert', 'core',
                   'crypto', 'internal', 'io', 'isolate',
@@ -236,7 +235,7 @@
              join(RESOURCE, '7zip'),
              ignore=ignore_patterns('.svn'))
 
-  # Copy dart2js/dartdoc/pub.
+  # Copy dart2js/pub.
   CopyDartScripts(HOME, SDK_tmp)
   CopySnapshots(SNAPSHOT, SDK_tmp)
 
diff --git a/tools/create_tarball.py b/tools/create_tarball.py
new file mode 100755
index 0000000..71ed4a8
--- /dev/null
+++ b/tools/create_tarball.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2014, 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.
+#
+
+# Script to build a tarball of the Dart source.
+#
+# The tarball includes all the source needed to build Dart. This
+# includes source in third_party. As part of creating the tarball the
+# files used to build Debian packages are copied to a top-level debian
+# directory. This makes it easy to build Debian packages from the
+# tarball.
+#
+# For building a Debian package one need to the tarball to follow the
+# Debian naming rules upstream tar files.
+#
+#  $ mv dart-XXX.tar.gz dart_XXX.orig.tar.gz
+#  $ tar xf dart_XXX.orig.tar.gz
+#  $ cd dart_XXX
+#  $ debuild -us -uc
+
+import datetime
+import optparse
+import sys
+import tarfile
+import utils
+
+from os import listdir, makedirs
+from os.path import join, exists, split, dirname, abspath
+
+HOST_OS = utils.GuessOS()
+DART_DIR = abspath(join(__file__, '..', '..'))
+
+# TODO (16582): Remove this when the LICENSE file becomes part of
+# all checkouts.
+license = [
+  'This license applies to all parts of Dart that are not externally',
+  'maintained libraries. The external maintained libraries used by',
+  'Dart are:',
+  '',
+  '7-Zip - in third_party/7zip',
+  'JSCRE - in runtime/third_party/jscre',
+  'Ant - in third_party/apache_ant',
+  'args4j - in third_party/args4j',
+  'bzip2 - in third_party/bzip2',
+  'Commons IO - in third_party/commons-io',
+  'Commons Lang in third_party/commons-lang',
+  'dromaeo - in samples/third_party/dromaeo',
+  'Eclipse - in third_party/eclipse',
+  'gsutil - in third_party/gsutil',
+  'Guava - in third_party/guava',
+  'hamcrest - in third_party/hamcrest',
+  'Httplib2 - in samples/third_party/httplib2',
+  'JSON - in third_party/json',
+  'JUnit - in third_party/junit',
+  'Oauth - in samples/third_party/oauth2client',
+  'weberknecht - in third_party/weberknecht',
+  'fest - in third_party/fest',
+  'mockito - in third_party/mockito',
+  '',
+  'The libraries may have their own licenses; we recommend you read them,',
+  'as their terms may differ from the terms below.',
+  '',
+  'Copyright 2012, the Dart project authors. All rights reserved.',
+  'Redistribution and use in source and binary forms, with or without',
+  'modification, are permitted provided that the following conditions are',
+  'met:',
+  '    * Redistributions of source code must retain the above copyright',
+  '      notice, this list of conditions and the following disclaimer.',
+  '    * Redistributions in binary form must reproduce the above',
+  '      copyright notice, this list of conditions and the following',
+  '      disclaimer in the documentation and/or other materials provided',
+  '      with the distribution.',
+  '    * Neither the name of Google Inc. nor the names of its',
+  '      contributors may be used to endorse or promote products derived',
+  '      from this software without specific prior written permission.',
+  'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS',
+  '"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT',
+  'LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR',
+  'A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT',
+  'OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,',
+  'SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT',
+  'LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,',
+  'DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY',
+  'THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT',
+  '(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE',
+  'OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.'
+]
+
+# Flags.
+verbose = False
+
+# Name of the dart directory when unpacking the tarball.
+versiondir = ''
+
+# Ignore Git/SVN files, checked-in binaries, backup files, etc..
+ignoredPaths = ['tools/testing/bin'
+                'third_party/7zip', 'third_party/android_tools',
+                'third_party/clang', 'third_party/d8',
+                'third_party/firefox_jsshell']
+ignoredDirs = ['.svn', '.git']
+ignoredEndings = ['.mk', '.pyc', 'Makefile', '~']
+
+def BuildOptions():
+  result = optparse.OptionParser()
+  result.add_option("-v", "--verbose",
+      help='Verbose output.',
+      default=False, action="store_true")
+  return result
+
+def Filter(tar_info):
+  # Get the name of the file relative to the dart directory. Note the
+  # name from the TarInfo does not include a leading slash.
+  assert tar_info.name.startswith(DART_DIR[1:])
+  original_name = tar_info.name[len(DART_DIR):]
+  _, tail = split(original_name)
+  if tail in ignoredDirs:
+    return None
+  for path in ignoredPaths:
+    if original_name.startswith(path):
+      return None
+  for ending in ignoredEndings:
+    if original_name.endswith(ending):
+      return None
+  # Add the dart directory name with version. Place the debian
+  # directory one level over the rest which are placed in the
+  # directory 'dart'. This enables building the Debian packages
+  # out-of-the-box.
+  tar_info.name = join(versiondir, 'dart', original_name)
+  if verbose:
+    print 'Adding %s as %s' % (original_name, tar_info.name)
+  return tar_info
+
+def GenerateCopyright(filename):
+  license_lines = license
+  try:
+    # TODO (16582): The LICENSE file is currently not in a normal the
+    # dart checkout.
+    with open(join(DART_DIR, 'LICENSE')) as lf:
+      license_lines = lf.read().splitlines()
+  except:
+    pass
+
+  with open(filename, 'w') as f:
+    f.write('Name: dart\n')
+    f.write('Maintainer: Dart Team <misc@dartlang.org>\n')
+    f.write('Source: https://code.google.com/p/dart/\n')
+    f.write('License:\n')
+    for line in license_lines:
+      f.write(' %s\n' % line)
+
+def GenerateChangeLog(filename, version):
+  with open(filename, 'w') as f:
+    f.write('dart (%s-1) UNRELEASED; urgency=low\n' % version)
+    f.write('\n')
+    f.write('  * Generated file.\n')
+    f.write('\n')
+    f.write(' -- Dart Team <misc@dartlang.org>  %s\n' %
+            datetime.datetime.utcnow().strftime('%a, %d %b %Y %X +0000'))
+
+def GenerateSvnRevision(filename, svn_revision):
+  with open(filename, 'w') as f:
+    f.write(svn_revision)
+
+
+def CreateTarball():
+  global ignoredPaths  # Used for adding the output directory.
+  # Generate the name of the tarfile
+  version = utils.GetVersion()
+  global versiondir
+  versiondir = 'dart-%s' % version
+  tarname = '%s.tar.gz' % versiondir
+  debian_dir = 'tools/linux_dist_support/debian'
+  # Create the tar file in the build directory.
+  tardir = join(DART_DIR, utils.GetBuildDir(HOST_OS, HOST_OS))
+  # Don't include the build directory in the tarball.
+  ignoredPaths.append(tardir)
+  if not exists(tardir):
+    makedirs(tardir)
+  tarfilename = join(tardir, tarname)
+  print 'Creating tarball: %s' % tarfilename
+  with tarfile.open(tarfilename, mode='w:gz') as tar:
+    for f in listdir(DART_DIR):
+      tar.add(join(DART_DIR, f), filter=Filter)
+    for f in listdir(join(DART_DIR, debian_dir)):
+      tar.add(join(DART_DIR, debian_dir, f),
+              arcname='%s/debian/%s' % (versiondir, f))
+
+    with utils.TempDir() as temp_dir:
+      # Generate and add debian/copyright
+      copyright = join(temp_dir, 'copyright')
+      GenerateCopyright(copyright)
+      tar.add(copyright, arcname='%s/debian/copyright' % versiondir)
+
+      # Generate and add debian/changelog
+      change_log = join(temp_dir, 'changelog')
+      GenerateChangeLog(change_log, version)
+      tar.add(change_log, arcname='%s/debian/changelog' % versiondir)
+
+      # For bleeding_edge add the SVN_REVISION file.
+      if utils.GetChannel() == 'be':
+        svn_revision = join(temp_dir, 'SVN_REVISION')
+        GenerateSvnRevision(svn_revision, utils.GetSVNRevision())
+        tar.add(svn_revision, arcname='%s/dart/tools/SVN_REVISION' % versiondir)
+
+def Main():
+  if HOST_OS != 'linux':
+    print 'Tarball can only be created on linux'
+    return -1
+
+  # Parse the options.
+  parser = BuildOptions()
+  (options, args) = parser.parse_args()
+  if options.verbose:
+    global verbose
+    verbose = True
+
+  CreateTarball()
+
+if __name__ == '__main__':
+  sys.exit(Main())
diff --git a/tools/dom/docs/lib/docs.dart b/tools/dom/docs/lib/docs.dart
index e7c4abf..62ca836 100644
--- a/tools/dom/docs/lib/docs.dart
+++ b/tools/dom/docs/lib/docs.dart
@@ -11,7 +11,7 @@
 library docs;
 
 import '../../../../sdk/lib/_internal/dartdoc/lib/src/dart2js_mirrors.dart';
-import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
 import '../../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
 import '../../../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
 import '../../../../sdk/lib/_internal/dartdoc/lib/src/json_serializer.dart';
@@ -93,15 +93,17 @@
 
     var libraryJson = {};
     var sortedClasses = _sortAndFilterMirrors(
-        libMirror.classes.values.toList(), ignoreDocsEditable: true);
+        classesOf(libMirror.declarations).toList(), ignoreDocsEditable: true);
 
     for (ClassMirror classMirror in sortedClasses) {
+      print(' class: $classMirror');
       var classJson = {};
       var sortedMembers = _sortAndFilterMirrors(
-          classMirror.members.values.toList());
+          membersOf(classMirror.declarations).toList());
 
       var membersJson = {};
       for (var memberMirror in sortedMembers) {
+        print('  member: $memberMirror');
         var memberDomName = domNames(memberMirror)[0];
         var memberComment = _splitCommentsByNewline(
             computeUntrimmedCommentAsList(memberMirror));
@@ -136,7 +138,7 @@
     }
 
     if (!libraryJson.isEmpty) {
-      convertedJson.putIfAbsent(libMirror.simpleName, () =>
+      convertedJson.putIfAbsent(nameOf(libMirror), () =>
           libraryJson);
     }
   }
@@ -182,7 +184,7 @@
 
   if (domNameMetadata != null) {
     var domNames = <String>[];
-    var tags = domNameMetadata.getField('name');
+    var tags = domNameMetadata.getField(#name);
     for (var s in tags.reflectee.split(',')) {
       domNames.add(s.trim());
     }
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index c234928..d1c9c3f 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -971,7 +971,6 @@
 
     if requires_stack_info:
       self._cpp_impl_includes.add('"ScriptArguments.h"')
-      self._cpp_impl_includes.add('"ScriptCallStack.h"')
       body_emitter.Emit(
           '\n'
           '        ScriptState* currentState = DartUtilities::currentScriptState();\n'
@@ -984,10 +983,7 @@
           '        Dart_Handle customArgument = Dart_GetNativeArgument(args, $INDEX);\n'
           '        RefPtr<ScriptArguments> scriptArguments(DartUtilities::createScriptArguments(customArgument, exception));\n'
           '        if (!scriptArguments)\n'
-          '            goto fail;\n'
-          '        RefPtr<ScriptCallStack> scriptCallStack(DartUtilities::createScriptCallStack());\n'
-          '        if (!scriptCallStack->size())\n'
-          '            return;\n',
+          '            goto fail;\n',
           INDEX=len(arguments) + 1)
 
     if requires_script_arguments:
diff --git a/tools/dom/src/EventStreamProvider.dart b/tools/dom/src/EventStreamProvider.dart
index 2e787bd..85b4d78 100644
--- a/tools/dom/src/EventStreamProvider.dart
+++ b/tools/dom/src/EventStreamProvider.dart
@@ -223,13 +223,14 @@
     _tryResume();
   }
 
-  void cancel() {
-    if (_canceled) return;
+  Future cancel() {
+    if (_canceled) return null;
 
     _unlisten();
     // Clear out the target to indicate this is complete.
     _target = null;
     _onData = null;
+    return null;
   }
 
   bool get _canceled => _target == null;
diff --git a/tools/dom/src/KeyboardEventStream.dart b/tools/dom/src/KeyboardEventStream.dart
index b7e1607..520ac87 100644
--- a/tools/dom/src/KeyboardEventStream.dart
+++ b/tools/dom/src/KeyboardEventStream.dart
@@ -76,7 +76,7 @@
    * KeyboardEvent controller.
    */
   _KeyboardEventHandler(this._type): super(_EVENT_TYPE),
-      _stream = new _CustomKeyEventStreamImpl('event');
+      _stream = new _CustomKeyEventStreamImpl('event'), _target = null;
 
   /**
    * Hook up all event listeners under the covers so we can estimate keycodes
diff --git a/tools/dom/src/dart2js_CustomElementSupport.dart b/tools/dom/src/dart2js_CustomElementSupport.dart
index b622190..aa1c037 100644
--- a/tools/dom/src/dart2js_CustomElementSupport.dart
+++ b/tools/dom/src/dart2js_CustomElementSupport.dart
@@ -8,6 +8,10 @@
   return (receiver) {
     setNativeSubclassDispatchRecord(receiver, interceptor);
 
+    // Mirrors uses the constructor property to cache lookups, so we need it to
+    // be set correctly, including on IE where it is not automatically picked
+    // up from the __proto__.
+    JS('', '#.constructor = #.__proto__.constructor', receiver, receiver);
     return JS('', '#(#)', constructor, receiver);
   };
 }
diff --git a/tools/dom/src/native_DOMImplementation.dart b/tools/dom/src/native_DOMImplementation.dart
index 23d9931..d7a3fe6 100644
--- a/tools/dom/src/native_DOMImplementation.dart
+++ b/tools/dom/src/native_DOMImplementation.dart
@@ -406,7 +406,7 @@
     // TODO(vsm): Move these checks into native code.
     ClassMirror cls = reflectClass(type);
     if (_isBuiltinType(cls)) {
-      throw new UnsupportedError("Invalid custom element from $libName.");
+      throw new UnsupportedError("Invalid custom element from ${cls.owner.uri}.");
     }
     var className = MirrorSystem.getName(cls.simpleName);
     var createdConstructor = cls.declarations[new Symbol('$className.created')];
@@ -513,6 +513,9 @@
   int get length => Maps.length(this);
   bool get isEmpty => Maps.isEmpty(this);
   bool get isNotEmpty => Maps.isNotEmpty(this);
+  void addAll(Map<String, String> other) {
+    other.forEach((key, value) => this[key] = value);
+  }
 }
 
 final _printClosure = window.console.log;
diff --git a/tools/dom/src/shared_html.dart b/tools/dom/src/shared_html.dart
index c44effc..7c4f696 100644
--- a/tools/dom/src/shared_html.dart
+++ b/tools/dom/src/shared_html.dart
@@ -4,14 +4,16 @@
 
 part of dart.dom.html;
 
-_wrapZone(callback) {
+_wrapZone(callback(arg)) {
   // For performance reasons avoid wrapping if we are in the root zone.
   if (Zone.current == Zone.ROOT) return callback;
+  if (callback == null) return null;
   return Zone.current.bindUnaryCallback(callback, runGuarded: true);
 }
 
-_wrapBinaryZone(callback) {
+_wrapBinaryZone(callback(arg1, arg2)) {
   if (Zone.current == Zone.ROOT) return callback;
+  if (callback == null) return null;
   return Zone.current.bindBinaryCallback(callback, runGuarded: true);
 }
 
diff --git a/tools/dom/templates/html/impl/impl_WebGLRenderingContext.darttemplate b/tools/dom/templates/html/impl/impl_WebGLRenderingContext.darttemplate
index d04c3bb..bec16f9 100644
--- a/tools/dom/templates/html/impl/impl_WebGLRenderingContext.darttemplate
+++ b/tools/dom/templates/html/impl/impl_WebGLRenderingContext.darttemplate
@@ -67,11 +67,11 @@
 $if DART2JS
   @JSName('texSubImage2D')
   void texSubImage2DUntyped(int targetTexture, int levelOfDetail,
-      int internalFormat, int format, int type, data) native;
+      int xOffset, int yOffset, int format, int type, data) native;
 $else
   void texSubImage2DUntyped(int targetTexture, int levelOfDetail, 
-      int internalFormat, int format, int type, data) {
-    texSubImage2D(targetTexture, levelOfDetail, internalFormat,
+      int xOffset, int yOffset, int format, int type, data) {
+    texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset,
         format, type, data);
   }
 $endif
@@ -82,14 +82,14 @@
 $if DART2JS
   @JSName('texSubImage2D')
   void texSubImage2DTyped(int targetTexture, int levelOfDetail,
-      int internalFormat, int width, int height, int border, int format,
+      int xOffset, int yOffset, int width, int height, int border, int format,
       int type, TypedData data) native;
 $else
   void texSubImage2DTyped(int targetTexture, int levelOfDetail,
-      int internalFormat, int width, int height, int border, int format,
+      int xOffset, int yOffset, int width, int height, int format,
       int type, TypedData data) {
-    texSubImage2D(targetTexture, levelOfDetail, internalFormat,
-        width, height, border, format, type, data);
+    texSubImage2D(targetTexture, levelOfDetail, xOffset, yOffset,
+        width, height, format, type, data);
   }
 $endif
 }
diff --git a/tools/full-coverage.dart b/tools/full-coverage.dart
index b16f944..bafc0d1 100644
--- a/tools/full-coverage.dart
+++ b/tools/full-coverage.dart
@@ -6,7 +6,6 @@
 import "dart:convert";
 import "dart:io";
 import "dart:isolate";
-import "dart:mirrors";
 
 import "package:args/args.dart";
 import "package:path/path.dart";
@@ -189,7 +188,7 @@
     hitMap[source][line] += count;
   }
 
-  JSON.decode(rawJson).forEach((Map e) {
+  JSON.decode(rawJson)['coverage'].forEach((Map e) {
     String source = resolver.resolve(e["source"]);
     if (source == null) {
       // Couldnt resolve import, so skip this entry.
@@ -255,58 +254,78 @@
   return [new File(absPath)];
 }
 
-worker() {
+worker(WorkMessage msg) {
   final start = new DateTime.now().millisecondsSinceEpoch;
-  String me = currentMirrorSystem().isolate.debugName;
 
-  port.receive((Message message, reply) {
-    if (message.type == Message.SHUTDOWN) {
-      port.close();
+  var env = msg.environment;
+  List files = msg.files;
+  Resolver resolver = new Resolver(env);
+  var workerHitmap = {};
+  files.forEach((File fileEntry) {
+    // Read file sync, as it only contains 1 object.
+    String contents = fileEntry.readAsStringSync();
+    if (contents.length > 0) {
+      mergeHitmaps(createHitmap(contents, resolver), workerHitmap);
     }
-
-    if (message.type == Message.WORK) {
-      var env = message.payload[0];
-      List files = message.payload[1];
-      Resolver resolver = new Resolver(env);
-      var workerHitmap = {};
-      files.forEach((File fileEntry) {
-        // Read file sync, as it only contains 1 object.
-        String contents = fileEntry.readAsStringSync();
-        if (contents.length > 0) {
-          mergeHitmaps(createHitmap(contents, resolver), workerHitmap);
-        }
-      });
-      if (env["verbose"]) {
-        final end = new DateTime.now().millisecondsSinceEpoch;
-        print("worker[${me}]: Finished processing files. "
-              "Took ${end - start} ms.");
-      }
-      reply.send(new Message(Message.RESULT, [workerHitmap, resolver.failed]));
-    }
-
   });
+
+  if (env["verbose"]) {
+    final end = new DateTime.now().millisecondsSinceEpoch;
+    print("${msg.workerName}: Finished processing ${files.length} files. "
+          "Took ${end - start} ms.");
+  }
+
+  msg.replyPort.send(new ResultMessage(workerHitmap, resolver.failed));
 }
 
-class Message {
-  static const int SHUTDOWN = 1;
-  static const int RESULT = 2;
-  static const int WORK = 3;
+class WorkMessage {
+  final String workerName;
+  final Map environment;
+  final List files;
+  final SendPort replyPort;
+  WorkMessage(this.workerName, this.environment, this.files, this.replyPort);
+}
 
-  final int type;
-  final payload;
-
-  Message(this.type, this.payload);
+class ResultMessage {
+  final hitmap;
+  final failedResolves;
+  ResultMessage(this.hitmap, this.failedResolves);
 }
 
 final env = new Environment();
 
+List<List> split(List list, int nBuckets) {
+  var buckets = new List(nBuckets);
+  var bucketSize = list.length ~/ nBuckets;
+  var leftover = list.length % nBuckets;
+  var taken = 0;
+  var start = 0;
+  for (int i = 0; i < nBuckets; i++) {
+    var end = (i < leftover) ? (start + bucketSize + 1) : (start + bucketSize);
+    buckets[i] = list.sublist(start, end);
+    taken += buckets[i].length;
+    start = end;
+  }
+  if (taken != list.length) throw "Error splitting";
+  return buckets;
+}
+
+Future<ResultMessage> spawnWorker(name, environment, files) {
+  RawReceivePort port = new RawReceivePort();
+  var completer = new Completer();
+  port.handler = ((ResultMessage msg) {
+    completer.complete(msg);
+    port.close();
+  });
+  var msg = new WorkMessage(name, environment, files, port.sendPort);
+  Isolate.spawn(worker, msg);
+  return completer.future;
+}
+
 main(List<String> arguments) {
   parseArgs(arguments);
 
   List files = filesToProcess(env.input);
-  int filesPerWorker = files.length ~/ env.workers;
-  List workerPorts = [];
-  int doneCnt = 0;
 
   List failedResolves = [];
   List failedLoads = [];
@@ -321,57 +340,6 @@
     print("  package-root: ${env.pkgRoot}");
   }
 
-  port.receive((Message message, reply) {
-    if (message.type == Message.RESULT) {
-      mergeHitmaps(message.payload[0], globalHitmap);
-      failedResolves.addAll(message.payload[1]);
-      doneCnt++;
-    }
-
-    // All workers are done. Process the data.
-    if (doneCnt == env.workers) {
-      workerPorts.forEach((p) => p.send(new Message(Message.SHUTDOWN, null)));
-      if (env.verbose) {
-        final end = new DateTime.now().millisecondsSinceEpoch;
-        print("Done creating a global hitmap. Took ${end - start} ms.");
-      }
-
-      Future out;
-      if (env.prettyPrint) {
-        out = prettyPrint(globalHitmap, failedLoads);
-      }
-      if (env.lcov) {
-        out = lcov(globalHitmap);
-      }
-
-      out.then((_) {
-        env.output.close().then((_) {
-          if (env.verbose) {
-            final end = new DateTime.now().millisecondsSinceEpoch;
-            print("Done flushing output. Took ${end - start} ms.");
-          }
-        });
-        port.close();
-
-        if (env.verbose) {
-          if (failedResolves.length > 0) {
-            print("Failed to resolve:");
-            failedResolves.toSet().forEach((e) {
-              print("  ${e}");
-            });
-          }
-          if (failedLoads.length > 0) {
-            print("Failed to load:");
-            failedLoads.toSet().forEach((e) {
-              print("  ${e}");
-            });
-          }
-        }
-
-      });
-    }
-  });
-
   Map sharedEnv = {
     "sdkRoot": env.sdkRoot,
     "pkgRoot": env.pkgRoot,
@@ -379,22 +347,54 @@
   };
 
   // Create workers.
-  for (var i = 1; i < env.workers; i++) {
-    var p = spawnFunction(worker);
-    workerPorts.add(p);
-    var start = files.length - filesPerWorker;
-    var end = files.length;
-    var workerFiles = files.getRange(start, end).toList();
-    files.removeRange(start, end);
-    p.send(new Message(Message.WORK, [sharedEnv, workerFiles]), port);
-  }
-  // Let the last worker deal with the rest of the files (which should be only
-  // off by at max (#workers - 1).
-  var p = spawnFunction(worker);
-  workerPorts.add(p);
-  p.send(new Message(Message.WORK, [sharedEnv, files]), port.toSendPort());
+  int workerId = 0;
+  var results = split(files, env.workers).map((workerFiles) {
+    var result = spawnWorker("Worker ${workerId++}", sharedEnv, workerFiles);
+    return result.then((ResultMessage message) {
+      mergeHitmaps(message.hitmap, globalHitmap);
+      failedResolves.addAll(message.failedResolves);
+    });
+  });
 
-  return 0;
+  Future.wait(results).then((ignore) {
+    // All workers are done. Process the data.
+    if (env.verbose) {
+      final end = new DateTime.now().millisecondsSinceEpoch;
+      print("Done creating a global hitmap. Took ${end - start} ms.");
+    }
+
+    Future out;
+    if (env.prettyPrint) {
+      out = prettyPrint(globalHitmap, failedLoads);
+    }
+    if (env.lcov) {
+      out = lcov(globalHitmap);
+    }
+
+    out.then((_) {
+      env.output.close().then((_) {
+        if (env.verbose) {
+          final end = new DateTime.now().millisecondsSinceEpoch;
+          print("Done flushing output. Took ${end - start} ms.");
+        }
+      });
+
+      if (env.verbose) {
+        if (failedResolves.length > 0) {
+          print("Failed to resolve:");
+          failedResolves.toSet().forEach((e) {
+            print("  ${e}");
+          });
+        }
+        if (failedLoads.length > 0) {
+          print("Failed to load:");
+          failedLoads.toSet().forEach((e) {
+            print("  ${e}");
+          });
+        }
+      }
+    });
+  });
 }
 
 /// Checks the validity of the provided arguments. Does not initialize actual
diff --git a/tools/line_doc_comments.dart b/tools/line_doc_comments.dart
index 855648a..5f3448c 100755
--- a/tools/line_doc_comments.dart
+++ b/tools/line_doc_comments.dart
@@ -21,10 +21,10 @@
   }
 
   var dir = new Directory(args[0]);
-  dir.list(recursive: true).listen(
+  dir.list(recursive: true, followLinks: false).listen(
       (entity) {
         if (entity is File) {
-          var file = entity.name;
+          var file = entity.path;
           if (path.extension(file) != '.dart') return;
           fixFile(file);
         }
@@ -33,10 +33,10 @@
 
 void fixFile(String path) {
   var file = new File(path);
-  file.readAsLines().transform(fixContents).chain((fixed) {
+  file.readAsLines().then(fixContents).then((fixed) {
     return new File(path).writeAsString(fixed);
   }).then((file) {
-    print(file.name);
+    print(file.path);
   });
 }
 
@@ -54,14 +54,24 @@
         line = null;
       } else {
         var match = blockLine.firstMatch(line);
-        line = '$indent/// ${match[1]}';
+        var comment = match[1];
+        if (comment != '') {
+          line = '$indent/// $comment';
+        } else {
+          line = '$indent///';
+        }
       }
     } else {
       // See if it's a one-line block comment like: /** Blah. */
       var match = oneLineBlock.firstMatch(line);
       if (match != null) {
-        if (match[2] != '') {
-          line = '${match[1]}/// ${match[2]}';
+        var comment = match[2];
+        if (comment != '') {
+          // Remove the extra space before the `*/`
+          if (comment.endsWith(' ')) {
+            comment = comment.substring(0, comment.length - 1);
+          }
+          line = '${match[1]}/// $comment';
         } else {
           line = '${match[1]}///';
         }
diff --git a/tools/linux_dist_support/debian/compat b/tools/linux_dist_support/debian/compat
new file mode 100644
index 0000000..7f8f011
--- /dev/null
+++ b/tools/linux_dist_support/debian/compat
@@ -0,0 +1 @@
+7
diff --git a/tools/linux_dist_support/debian/control b/tools/linux_dist_support/debian/control
new file mode 100644
index 0000000..bc8c570
--- /dev/null
+++ b/tools/linux_dist_support/debian/control
@@ -0,0 +1,16 @@
+Source: dart
+Maintainer: Soren Gjesse <sgjesse@google.com>
+Section: misc
+Priority: optional
+Standards-Version: 3.9.2
+Build-Depends: debhelper (>= 9),
+	subversion,
+	python,
+	g++-4.6,
+	openjdk-6-jdk
+
+Package: dart
+Architecture: amd64 i386
+Depends: ${shlibs:Depends}, ${misc:Depends}
+Description: Dart SDK
+
diff --git a/tools/linux_dist_support/debian/dart.install b/tools/linux_dist_support/debian/dart.install
new file mode 100644
index 0000000..0ea869a
--- /dev/null
+++ b/tools/linux_dist_support/debian/dart.install
@@ -0,0 +1,2 @@
+debian/tmp/out/dart usr/lib
+
diff --git a/tools/linux_dist_support/debian/dart.links b/tools/linux_dist_support/debian/dart.links
new file mode 100644
index 0000000..30c3b93
--- /dev/null
+++ b/tools/linux_dist_support/debian/dart.links
@@ -0,0 +1,2 @@
+usr/lib/dart/bin/dart usr/bin/dart
+
diff --git a/tools/linux_dist_support/debian/rules b/tools/linux_dist_support/debian/rules
new file mode 100755
index 0000000..e733811
--- /dev/null
+++ b/tools/linux_dist_support/debian/rules
@@ -0,0 +1,51 @@
+#!/usr/bin/make -f
+export DH_VERBOSE = 1
+
+# Use DEB_BUILD_OPTIONS's parallel=n option (see Policy 4.9.1)
+ifneq (,$(findstring parallel,$(DEB_BUILD_OPTIONS)))
+PARALLEL_JOBS := $(shell echo $(DEB_BUILD_OPTIONS) | \
+	sed -e 's/.*parallel=\([0-9]\+\).*/\1/')
+else
+PARALLEL_JOBS := 1
+endif
+
+DEB_HOST_ARCH_CPU := $(shell dpkg-architecture -qDEB_HOST_ARCH_CPU)
+ifeq (amd64,$(DEB_HOST_ARCH_CPU))
+BUILD_TYPE += ReleaseX64
+else
+ifeq (i386,$(DEB_HOST_ARCH_CPU))
+BUILD_TYPE += ReleaseIA32
+else
+$(warning unsupported target arch $(DEB_HOST_ARCH_CPU) - continuing anyway)
+endif
+endif
+
+# Verbose?
+ifeq (1,$(DH_VERBOSE))
+BUILD_ARGS += V=1
+endif
+
+%:
+	dh $@
+
+override_dh_auto_clean:
+	echo $(DEB_BUILD_OPTIONS)
+	rm -fr dart/out dart/Makefile
+	find . -name *.tmp -execdir rm -f {} \;
+	find . -name *.pyc -execdir rm -f {} \;
+	find . -name *.mk -execdir rm -f {} \;
+	find . -name *.Makefile -execdir rm -f {} \;
+
+override_dh_auto_configure:
+	GYP_GENERATORS=make python dart/tools/gyp_dart.py all
+
+override_dh_auto_build:
+	make -C dart -j$(PARALLEL_JOBS) \
+		BUILDTYPE=$(BUILD_TYPE) $(BUILD_ARGS) create_sdk
+
+override_dh_auto_install:
+	mkdir -p debian/tmp/out
+	cp -R dart/out/$(BUILD_TYPE)/dart-sdk debian/tmp/out
+	mv debian/tmp/out/dart-sdk debian/tmp/out/dart
+	dh_install
+	dh_link
diff --git a/tools/linux_dist_support/debian/source/format b/tools/linux_dist_support/debian/source/format
new file mode 100644
index 0000000..163aaf8
--- /dev/null
+++ b/tools/linux_dist_support/debian/source/format
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/tools/test.dart b/tools/test.dart
index 27d0370..a0f5525 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -65,10 +65,6 @@
     new Path('utils/tests/css'),
     new Path('utils/tests/peg'),
     new Path('sdk/lib/_internal/pub'),
-    // TODO(amouravski): move these to tests/ once they no longer rely on weird
-    // dependencies.
-    new Path('sdk/lib/_internal/dartdoc'),
-    new Path('tools/dom/docs'),
 ];
 
 void testConfigurations(List<Map> configurations) {
diff --git a/tools/utils.py b/tools/utils.py
index 1c460fc..49ff0b1 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -339,6 +339,14 @@
   if revision:
     return revision
 
+  # When building from tarball use tools/SVN_REVISION
+  svn_revision_file = os.path.join(DART_DIR, 'tools', 'SVN_REVISION')
+  try:
+    with open(svn_revision_file) as fd:
+      return fd.read()
+  except:
+    pass
+
   # Only fail on the buildbot in case of a SVN client version mismatch.
   user = GetUserName()
   if user != 'chrome-bot':
diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart
index 326cce2..a9604f5 100644
--- a/utils/apidoc/apidoc.dart
+++ b/utils/apidoc/apidoc.dart
@@ -21,7 +21,7 @@
 import 'html_diff.dart';
 
 // TODO(rnystrom): Use "package:" URL (#4968).
-import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
 import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
 import '../../sdk/lib/_internal/compiler/implementation/filenames.dart';
 import '../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
@@ -305,7 +305,7 @@
         includeMdnTypeComment(type), super.getTypeComment(type));
   }
 
-  DocComment getMemberComment(MemberMirror member) {
+  DocComment getMemberComment(DeclarationMirror member) {
     return _mergeDocs(
         includeMdnMemberComment(member), super.getMemberComment(member));
   }
@@ -360,7 +360,7 @@
   MdnComment lookupMdnComment(Mirror mirror) {
     if (mirror is TypeMirror) {
       return includeMdnTypeComment(mirror);
-    } else if (mirror is MemberMirror) {
+    } else if (mirror is MethodMirror || mirror is VariableMirror) {
       return includeMdnMemberComment(mirror);
     } else {
       return null;
@@ -377,7 +377,7 @@
     }
 
     var typeString = '';
-    if (HTML_LIBRARY_URIS.contains(type.library.uri)) {
+    if (HTML_LIBRARY_URIS.contains(getLibrary(type).uri)) {
       // If it's an HTML type, try to map it to a base DOM type so we can find
       // the MDN docs.
       final domTypes = _diff.htmlTypesToDom[type.qualifiedName];
@@ -411,8 +411,8 @@
    * Gets the MDN-scraped docs for [member], or `null` if this type isn't
    * scraped from MDN.
    */
-  MdnComment includeMdnMemberComment(MemberMirror member) {
-    var library = findLibrary(member);
+  MdnComment includeMdnMemberComment(DeclarationMirror member) {
+    var library = getLibrary(member);
     var memberString = '';
     if (HTML_LIBRARY_URIS.contains(library.uri)) {
       // If it's an HTML type, try to map it to a DOM type name so we can find
@@ -464,7 +464,7 @@
    * Returns a link to [member], relative to a type page that may be in a
    * different library than [member].
    */
-  String _linkMember(MemberMirror member) {
+  String _linkMember(DeclarationMirror member) {
     final typeName = member.owner.simpleName;
     var memberName = '$typeName.${member.simpleName}';
     if (member is MethodMirror && member.isConstructor) {
diff --git a/utils/apidoc/apidoc.gyp b/utils/apidoc/apidoc.gyp
deleted file mode 100644
index 3c41afe..0000000
--- a/utils/apidoc/apidoc.gyp
+++ /dev/null
@@ -1,108 +0,0 @@
-# Copyright (c) 2012, 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.
-
-{
-  'variables' : {
-    'script_suffix%': '',
-  },
-  'conditions' : [
-    ['OS=="win"', {
-      'variables' : {
-        'script_suffix': '.bat',
-      },
-    }],
-  ],
-  'targets': [
-    {
-      'target_name': 'api_docs',
-      'type': 'none',
-      'dependencies': [
-        '../../utils/compiler/compiler.gyp:dart2js',
-        '../../runtime/dart-runtime.gyp:dart',
-        '../../pkg/pkg.gyp:pkg_packages',
-      ],
-      'includes': [
-        '../../sdk/lib/core/corelib_sources.gypi',
-      ],
-      'actions': [
-        {
-          'action_name': 'run_apidoc',
-          # The 'inputs' list records the files whose timestamps are
-          # compared to the files listed in 'outputs'.  If a file
-          # 'outputs' doesn't exist or if a file in 'inputs' is newer
-          # than a file in 'outputs', this action is executed.  Notice
-          # that the dependencies listed above has nothing to do with
-          # when this action is executed.  You must list a file in
-          # 'inputs' to make sure that it exists before the action is
-          # executed, or to make sure this action is re-run.
-          #
-          # We want to build the platform documentation whenever
-          # dartdoc, apidoc, or its dependency changes.  This prevents
-          # people from accidentally breaking apidoc when making
-          # changes to the platform libraries and or when modifying
-          # dart2js or the VM.
-          #
-          # In addition, we want to make sure that the platform
-          # documentation is regenerated when the platform sources
-          # changes.
-          #
-          # So we want this action to be re-run when a dart file
-          # changes in this directory, or in the SDK library (we may
-          # no longer need to list the files in ../../runtime/lib and
-          # ../../runtime/bin, as most of them has moved to
-          # ../../sdk/lib).
-          #
-          # In addition, we want to make sure the documentation is
-          # regenerated when a resource file (CSS, PNG, etc) is
-          # updated.  This is because these files are also copied to
-          # the output directory.
-          'inputs': [
-            '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
-            '<(SHARED_INTERMEDIATE_DIR)/utils_wrapper.dart.snapshot',
-            '<!@(["python", "../../tools/list_files.py", "\\.(css|ico|js|json|png|sh|txt|yaml|py)$", ".", "../../sdk/lib/_internal/dartdoc"])',
-            '<!@(["python", "../../tools/list_files.py", "\\.dart$", ".", "../../sdk/lib", "../../runtime/lib", "../../runtime/bin"])',
-            '../../sdk/bin/dart',
-            '../../sdk/bin/dart.bat',
-            '../../sdk/bin/dart2js',
-            '../../sdk/bin/dart2js.bat',
-            '../../tools/only_in_release_mode.py',
-          ],
-          'outputs': [
-            '<(PRODUCT_DIR)/api_docs/index.html',
-            '<(PRODUCT_DIR)/api_docs/client-static.js',
-          ],
-          'action': [
-            'python',
-            '../../tools/only_in_release_mode.py',
-            '<@(_outputs)',
-            '--',
-            '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart<(EXECUTABLE_SUFFIX)',
-            '--package-root=<(PRODUCT_DIR)/packages/',
-            'apidoc.dart',
-            '--out=<(PRODUCT_DIR)/api_docs',
-            '--version=<!@(["python", "../../tools/print_version.py"])',
-            '--package-root=<(PRODUCT_DIR)/packages',
-            '--mode=static',
-            '--exclude-lib=analyzer',
-            '--exclude-lib=async_helper',
-            '--exclude-lib=barback',
-            '--exclude-lib=browser',
-            '--exclude-lib=dartdoc',
-            '--exclude-lib=docgen',
-            '--exclude-lib=expect',
-            '--exclude-lib=oauth2',
-            '--exclude-lib=scheduled_test',
-            '--exclude-lib=stack_trace',
-            '--exclude-lib=watcher',
-            '--exclude-lib=webdriver',
-            '--exclude-lib=yaml',
-            '--include-lib=matcher',
-            '--extra-lib=pkg/unittest/lib/mock.dart',
-          ],
-          'message': 'Running apidoc: <(_action)',
-        },
-      ],
-    }
-  ],
-}
diff --git a/utils/apidoc/docgen.gyp b/utils/apidoc/docgen.gyp
index 51889c0..d57e9c3 100644
--- a/utils/apidoc/docgen.gyp
+++ b/utils/apidoc/docgen.gyp
@@ -21,7 +21,6 @@
         '../../utils/compiler/compiler.gyp:dart2js',
         '../../runtime/dart-runtime.gyp:dart',
         '../../pkg/pkg.gyp:pkg_packages',
-        'apidoc.gyp:api_docs',
       ],
       'includes': [
         '../../sdk/lib/core/corelib_sources.gypi',
@@ -66,9 +65,6 @@
             '../../sdk/bin/docgen',
             '../../sdk/bin/docgen.bat',
             '../../tools/only_in_release_mode.py',
-            # We sit inside the api_docs directory, so make sure it has run
-            # before we do. Otherwise it might run later and delete us.
-            '<(PRODUCT_DIR)/api_docs/index.html',
           ],
           'outputs': [
             '<(PRODUCT_DIR)/api_docs/docgen/index.json',
@@ -78,7 +74,9 @@
             '../../tools/only_in_release_mode.py',
             '<@(_outputs)',
             '--',
-            '<(PRODUCT_DIR)/<(EXECUTABLE_PREFIX)dart-sdk/bin/docgen<(script_suffix)',
+            '../../sdk/bin/dart',
+            '--package-root=<(PRODUCT_DIR)/packages',
+            '../../pkg/docgen/bin/docgen.dart',
             '--out=<(PRODUCT_DIR)/api_docs/docgen',
             '--json',
             '--include-sdk',
diff --git a/utils/apidoc/html_diff.dart b/utils/apidoc/html_diff.dart
index 45ae9dd..85c49c9 100644
--- a/utils/apidoc/html_diff.dart
+++ b/utils/apidoc/html_diff.dart
@@ -9,17 +9,14 @@
 library html_diff;
 
 import 'dart:async';
-import 'dart:io';
 
 import 'lib/metadata.dart';
 
 // TODO(rnystrom): Use "package:" URL (#4968).
-import '../../sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart';
-import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../sdk/lib/_internal/compiler/implementation/mirrors/analyze.dart';
+import '../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
 import '../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
 import '../../sdk/lib/_internal/compiler/implementation/source_file_provider.dart';
-import '../../sdk/lib/_internal/dartdoc/lib/dartdoc.dart';
-import '../../sdk/lib/html/html_common/metadata.dart';
 
 // TODO(amouravski): There is currently magic that looks at dart:* libraries
 // rather than the declared library names. This changed due to recent syntax
@@ -103,15 +100,15 @@
           warn('Could not find $libraryUri');
           result.complete(false);
         }
-        for (ClassMirror type in library.classes.values) {
+        for (ClassMirror type in classesOf(library.declarations)) {
           final domTypes = htmlToDomTypes(type);
           if (domTypes.isEmpty) continue;
 
-          htmlTypesToDom.putIfAbsent(type.qualifiedName,
+          htmlTypesToDom.putIfAbsent(qualifiedNameOf(type),
               () => new Set()).addAll(domTypes);
 
-          type.members.forEach(
-              (_, m) => _addMemberDiff(m, domTypes, library.simpleName));
+          membersOf(type.declarations).forEach(
+              (m) => _addMemberDiff(m, domTypes, nameOf(library)));
         }
       }
       result.complete(true);
@@ -125,7 +122,7 @@
    * `@DomName` type values that correspond to [htmlMember]'s
    * defining type.
    */
-  void _addMemberDiff(MemberMirror htmlMember, List<String> domTypes,
+  void _addMemberDiff(DeclarationMirror htmlMember, List<String> domTypes,
       String libraryName) {
     var domMembers = htmlToDomMembers(htmlMember, domTypes);
     if (htmlMember == null && !domMembers.isEmpty) {
@@ -137,7 +134,7 @@
 
     if (htmlMember == null) return;
     if (!domMembers.isEmpty) {
-      htmlToDom[htmlMember.qualifiedName] = domMembers;
+      htmlToDom[qualifiedNameOf(htmlMember)] = domMembers;
     }
   }
 
@@ -152,7 +149,7 @@
     final domNameMetadata = findMetadata(htmlType.metadata, 'DomName');
     if (domNameMetadata != null) {
       var domNames = <String>[];
-      var names = domNameMetadata.getField('name');
+      var names = domNameMetadata.getField(symbolOf('name'));
       for (var s in names.reflectee.split(',')) {
         domNames.add(s.trim());
       }
@@ -170,13 +167,14 @@
    * `@DomName` type values that correspond to [htmlMember]'s
    * defining type.
    */
-  Set<String> htmlToDomMembers(MemberMirror htmlMember, List<String> domTypes) {
+  Set<String> htmlToDomMembers(DeclarationMirror htmlMember,
+                               List<String> domTypes) {
     if (htmlMember.isPrivate) return new Set();
 
     final domNameMetadata = findMetadata(htmlMember.metadata, 'DomName');
     if (domNameMetadata != null) {
       var domNames = <String>[];
-      var names = domNameMetadata.getField('name');
+      var names = domNameMetadata.getField(symbolOf('name'));
       for (var s in names.reflectee.split(',')) {
         domNames.add(s.trim());
       }
diff --git a/utils/apidoc/lib/metadata.dart b/utils/apidoc/lib/metadata.dart
index c0a848c..2881bc1 100644
--- a/utils/apidoc/lib/metadata.dart
+++ b/utils/apidoc/lib/metadata.dart
@@ -1,14 +1,15 @@
 library metadata;
 
-import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/source_mirrors.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/mirrors/mirrors_util.dart';
 
 /// Returns the metadata for the given string or null if not found.
 InstanceMirror findMetadata(List<InstanceMirror> metadataList, String find) {
   return metadataList.firstWhere(
       (metadata) {
         if (metadata is TypeInstanceMirror) {
-          return metadata.representedType.simpleName == find;
+          return nameOf(metadata.representedType) == find;
         }
-        return metadata.type.simpleName == find;
+        return nameOf(metadata.type) == find;
       }, orElse: () => null);
 }
diff --git a/utils/compiler/compiler.gyp b/utils/compiler/compiler.gyp
index 4f4ae14..fc4b1cf 100644
--- a/utils/compiler/compiler.gyp
+++ b/utils/compiler/compiler.gyp
@@ -34,7 +34,6 @@
             'create_snapshot.dart',
             '--output_dir=<(SHARED_INTERMEDIATE_DIR)',
             '--dart2js_main=sdk/lib/_internal/compiler/implementation/dart2js.dart',
-            '--dartdoc_main=sdk/lib/_internal/dartdoc/bin/dartdoc.dart',
             '--docgen_main=pkg/docgen/bin/docgen.dart',
             '--package_root=<(PRODUCT_DIR)/packages/',
           ],
diff --git a/utils/compiler/create_snapshot.dart b/utils/compiler/create_snapshot.dart
index f5f3b95..0123792 100644
--- a/utils/compiler/create_snapshot.dart
+++ b/utils/compiler/create_snapshot.dart
@@ -18,13 +18,11 @@
 
 Future<String> getSnapshotGenerationFile(var args, var rootPath) {
   var dart2js = rootPath.resolve(args["dart2js_main"]);
-  var dartdoc = rootPath.resolve(args["dartdoc_main"]);
   var docgen = rootPath.resolve(args["docgen_main"]);
   return getVersion(rootPath).then((version) {
     var snapshotGenerationText =
 """
 import '${dart2js.toFilePath(windows: false)}' as dart2jsMain;
-import '${dartdoc.toFilePath(windows: false)}' as dartdocMain;
 import '${docgen.toFilePath(windows: false)}' as docgenMain;
 import 'dart:io';
 
@@ -34,8 +32,6 @@
   if (tool == "dart2js") {
     dart2jsMain.BUILD_ID = "$version";
     dart2jsMain.main(arguments.skip(1).toList());
-  } else if (tool == "dartdoc") {
-    dartdocMain.main(arguments.skip(1).toList());
   } else if (tool == "docgen") {
     docgenMain.main(arguments.skip(1).toList());
   }
@@ -88,12 +84,11 @@
  * Takes the following arguments:
  * --output_dir=val     The full path to the output_dir.
  * --dart2js_main=val   The path to the dart2js main script relative to root.
- * --dartdoc_main=val   The path to the dartdoc main script relative to root.
  * --docgen_main=val    The path to the docgen main script relative to root.
  * --package-root=val   The package-root used to find packages for the snapshot.
  */
 void main(List<String> arguments) {
-  var validArguments = ["--output_dir", "--dart2js_main", "--dartdoc_main",
+  var validArguments = ["--output_dir", "--dart2js_main",
                         "--docgen_main", "--package_root"];
   var args = {};
   for (var argument in arguments) {
@@ -105,7 +100,6 @@
     args[argumentSplit[0].substring(2)] = argumentSplit[1];
   }
   if (!args.containsKey("dart2js_main")) throw "Please specify dart2js_main";
-  if (!args.containsKey("dartdoc_main")) throw "Please specify dartdoc_main";
   if (!args.containsKey("docgen_main")) throw "Please specify docgen_main";
   if (!args.containsKey("output_dir")) throw "Please specify output_dir";
   if (!args.containsKey("package_root")) throw "Please specify package_root";